javascript - produccion - node.js ejecuta el comando del sistema sincrónicamente
node js tutorial (12)
Necesito la función node.js
result = execSync(''node -v'');
que ejecutará de forma sincrónica la línea de comando dada y devolverá todo el código de comando estándar.
PD. La sincronización es incorrecta. Lo sé. Solo para uso personal.
ACTUALIZAR
¡Ahora tenemos la solución de mgutz que nos da el código de salida, pero no stdout! Todavía estoy esperando una respuesta más precisa.
ACTUALIZAR
mgutz actualizó su respuesta y la solución está aquí :)
Además, como se mencionó en dgo.a , existe exec-sync módulos independientes
ACTUALIZACIÓN 2014-07-30
ShellJS lib llegó. Considera que esta es la mejor opción por ahora.
ACTUALIZACIÓN 2015-02-10
¡AL FINAL! NodeJS 0.12 es compatible con execSync
forma nativa.
Ver docs oficiales
De hecho, tuve una situación en la que necesitaba ejecutar múltiples comandos uno tras otro desde un script de preinstalación de package.json de una manera que funcionara tanto en Windows como en Linux / OSX, por lo que no podía confiar en un módulo no principal.
Así que esto es lo que se me ocurrió:
#cmds.coffee
childproc = require ''child_process''
exports.exec = (cmds) ->
next = ->
if cmds.length > 0
cmd = cmds.shift()
console.log "Running command: #{cmd}"
childproc.exec cmd, (err, stdout, stderr) ->
if err? then console.log err
if stdout? then console.log stdout
if stderr? then console.log stderr
next()
else
console.log "Done executing commands."
console.log "Running the follows commands:"
console.log cmds
next()
Puedes usarlo así:
require(''./cmds'').exec [''grunt coffee'', ''nodeunit test/tls-config.js'']
EDITAR: como se señaló, esto en realidad no devuelve el resultado ni le permite usar el resultado de los comandos en un programa de nodo. Otra idea para eso es usar backcalls de LiveScript. http://livescript.net/
Esta es la forma más fácil que encontré:
exec-Sync : exec-sync
(No debe confundirse con execSync).
Ejecute el comando de shell de forma sincrónica. Úselo para scripts de migración, programas cli, pero no para el código de servidor normal.Ejemplo:
var execSync = require(''exec-sync'');
var user = execSync(''echo $USER'');
console.log(user);
Esto no es posible en Node.js, tanto child_process.spawn
como child_process.exec
se construyeron desde cero para ser asincrónicos.
Para detalles, ver: https://github.com/ry/node/blob/master/lib/child_process.js
Si realmente desea tener este bloqueo, luego coloque todo lo que necesita después en una devolución de llamada, o cree su propia cola para manejar esto de forma bloqueada, supongo que podría usar Async.js para esta tarea.
O, en caso de que tengas demasiado tiempo para gastar, piratea en Node.js.
Hay un módulo excelente para el control de flujo en node.js llamado asyncblock . Si envolver el código en una función es correcto para su caso, se puede considerar la siguiente muestra:
var asyncblock = require(''asyncblock'');
var exec = require(''child_process'').exec;
asyncblock(function (flow) {
exec(''node -v'', flow.add());
result = flow.wait();
console.log(result); // There''ll be trailing /n in the output
// Some other jobs
console.log(''More results like if it were sync...'');
});
Me acostumbro a implementar cosas "synchronous"
al final de la función de devolución de llamada. No es muy lindo, pero funciona. Si necesita implementar una secuencia de ejecuciones de línea de comando, debe ajustar el exec
en alguna función con nombre y llamarlo recursivamente. Este patrón parece ser útil para mí:
SeqOfExec(someParam);
function SeqOfExec(somepParam) {
// some stuff
// .....
// .....
var execStr = "yourExecString";
child_proc.exec(execStr, function (error, stdout, stderr) {
if (error != null) {
if (stdout) {
throw Error("Smth goes wrong" + error);
} else {
// consider that empty stdout causes
// creation of error object
}
}
// some stuff
// .....
// .....
// you also need some flag which will signal that you
// need to end loop
if (someFlag ) {
// your synch stuff after all execs
// here
// .....
} else {
SeqOfExec(someAnotherParam);
}
});
};
Node.js (desde la versión 0.12 - por lo que por un tiempo) es compatible con execSync
:
child_process.execSync(command[, options])
Ahora puede hacer esto directamente:
const execSync = require(''child_process'').execSync;
code = execSync(''node -v'');
y hará lo que esperas. (Predeterminadamente para canalizar los resultados de E / S al proceso principal). Tenga en cuenta que también puede spawnSync
ahora.
Puedes lograr esto usando fibras. Por ejemplo, al usar mi biblioteca Common Node , el código se vería así:
result = require(''subprocess'').command(''node -v'');
Solo para agregar que a pesar de que hay pocos usos donde debería usarlos, spawnSync
/ execFileSync
/ execSync
se agregaron a node.js en estos commits: https://github.com/joyent/node/compare/d58c206862dc...e8df2676748e
Tuve un problema similar y terminé escribiendo una extensión de nodo para esto. Puedes ver el repositorio de git. ¡Es de código abierto y gratuito y todas esas cosas buenas!
https://github.com/aponxi/npm-execxi
ExecXI es una extensión de nodo escrita en C ++ para ejecutar comandos de shell uno por uno, dando salida a la consola en tiempo real. Hay formas encadenadas y desencadenadas opcionales; lo que significa que puede optar por detener el script después de que falla un comando (encadenado), o puede continuar como si nada hubiera sucedido.
Las instrucciones de uso están en el archivo ReadMe . Siéntase libre de hacer solicitudes de extracción o enviar problemas!
EDITAR: Sin embargo, no devuelve el stdout todavía ... Simplemente los emite en tiempo real. Lo hace ahora. Bueno, acabo de lanzarlo hoy. Tal vez podamos construir sobre eso.
De todos modos, pensé que valía la pena mencionarlo.
Ver la biblioteca execSync .
Es bastante fácil de hacer con node-ffi . No lo recomendaría para los procesos de servidor, pero para las utilidades de desarrollo general hace las cosas. Instala la biblioteca.
npm install node-ffi
Script de ejemplo:
var FFI = require("node-ffi");
var libc = new FFI.Library(null, {
"system": ["int32", ["string"]]
});
var run = libc.system;
run("echo $USER");
[EDITAR jun 2012: cómo obtener STDOUT]
var lib = ffi.Library(null, {
// FILE* popen(char* cmd, char* mode);
popen: [''pointer'', [''string'', ''string'']],
// void pclose(FILE* fp);
pclose: [''void'', [ ''pointer'']],
// char* fgets(char* buff, int buff, in)
fgets: [''string'', [''string'', ''int'',''pointer'']]
});
function execSync(cmd) {
var
buffer = new Buffer(1024),
result = "",
fp = lib.popen(cmd, ''r'');
if (!fp) throw new Error(''execSync error: ''+cmd);
while(lib.fgets(buffer, 1024, fp)) {
result += buffer.readCString();
};
lib.pclose(fp);
return result;
}
console.log(execSync(''echo $HOME''));
puede hacer operaciones de shell sincrónicas en nodejs de esta manera:
var execSync = function(cmd) {
var exec = require(''child_process'').exec;
var fs = require(''fs'');
//for linux use ; instead of &&
//execute your command followed by a simple echo
//to file to indicate process is finished
exec(cmd + " > c://stdout.txt && echo done > c://sync.txt");
while (true) {
//consider a timeout option to prevent infinite loop
//NOTE: this will max out your cpu too!
try {
var status = fs.readFileSync(''c://sync.txt'', ''utf8'');
if (status.trim() == "done") {
var res = fs.readFileSync("c://stdout.txt", ''utf8'');
fs.unlinkSync("c://stdout.txt"); //cleanup temp files
fs.unlinkSync("c://sync.txt");
return res;
}
} catch(e) { } //readFileSync will fail until file exists
}
};
//won''t return anything, but will take 10 seconds to run
console.log(execSync("sleep 10"));
//assuming there are a lot of files and subdirectories,
//this too may take a while, use your own applicable file path
console.log(execSync("dir /s c://usr//docs//"));
EDITAR: este ejemplo está destinado a entornos de Windows, si es necesario, ajústelo para sus propias necesidades de Linux