tutorial - Ejecutando un comando de shell desde Node.js sin búfer de salida
npm (4)
Estoy intentando iniciar un comando de shell desde Node.js, sin redirigir la entrada y salida de ese comando, como si se tratara de un comando de shell o un comando del system
de Ruby. Si el proceso hijo desea escribir en STDOUT, quiero que vaya directamente a la consola (o se redirija, si se redirige la salida de mi aplicación Node).
Node no parece tener una manera directa de hacer esto. Parece que la única forma de ejecutar otro proceso es con child_process
, que siempre redirige la entrada y salida del proceso hijo a las canalizaciones. Puedo escribir código para aceptar datos de esas canalizaciones y escribirlos en STDOUT y STDERR de mi proceso, pero si lo hago, las API me obligan a sacrificar cierta flexibilidad.
Quiero dos características:
- Sintaxis de shell. Quiero poder canalizar la salida entre comandos o ejecutar archivos por lotes de Windows.
- Salida ilimitada. Si estoy disparando a un compilador y quiere generar megabytes de avisos de compilación, quiero que todos se desplacen por la pantalla (hasta que el usuario se canse de él y presione Ctrl + C).
Parece que Node quiere forzarme a elegir entre esas dos características.
- Si quiero una cantidad ilimitada de salida, puedo usar
child_process.spawn
y luego hacerchild.stdout.on(''data'', function(data) { process.stdout.write(data); });
y lo mismo parastderr
, y felizmente canalizará datos hasta que las vacas vuelvan a casa. Desafortunadamente,spawn
no soporta la sintaxis de shell. - Si quiero sintaxis de shell, puedo usar
child_process.exec
. Peroexec
insiste en almacenar en búfer los procesos STDOUT y STDERR del proceso hijo para mí y dárselos a todos al final, y limita el tamaño de esos búferes (configurables, 200K por defecto). Todavía puedo conectar los eventoson(''data'')
, si quiero ver la salida a medida que se genera, peroexec
también agregará los datos a sus búferes. Cuando la cantidad de datos excede el tamaño del búfer predefinido,exec
terminará el proceso hijo.
(También hay child_process.execFile
, que es el peor de los dos mundos desde el punto de vista de la flexibilidad: no hay sintaxis de shell, pero aún tiene que limitar la cantidad de salida que espera).
¿Me estoy perdiendo de algo? ¿Hay alguna forma de pagar un proceso secundario en Nodo y no redirigir su entrada y salida? ¿Algo que admita la sintaxis de shell y que no cague después de una cantidad predefinida de salida, al igual que está disponible en los scripts de shell, Ruby, etc.?
Hay un ejemplo en los child_process.spawn del child_process.spawn para el módulo child_process:
Ejemplo de separar un proceso de larga duración y redirigir su salida a un archivo:
var fs = require(''fs''),
spawn = require(''child_process'').spawn,
out = fs.openSync(''./out.log'', ''a''),
err = fs.openSync(''./out.log'', ''a'');
var child = spawn(''prg'', [], {
detached: true,
stdio: [ ''ignore'', out, err ]
});
child.unref();
No lo he usado, pero he visto esta biblioteca: https://github.com/polotek/procstreams
Lo harías tú. El .out()
canaliza automáticamente a la entrada / salida estándar del proceso.
var $p = require(''procstreams'');
$p(''cat lines.txt'').pipe(''wc -l'').out();
Si no es compatible con la sintaxis de shell, pero creo que eso es bastante trivial.
var command_str = "cat lines.txt | wc -l";
var cmds = command_str.split(//s?/|/s?/);
var cmd = $p(cmds.shift());
while(cmds.length) cmd = cmd.pipe(cmds.shift());
cmd
.out()
.on(''exit'', function() {
// Do whatever
});
Puede heredar stdin / out / error streams a través del argumento spawn
por lo que no necesita canalizarlos manualmente:
var spawn = require(''child_process'').spawn;
spawn(''ls'', [], { stdio: ''inherit'' });
Use shell para la sintaxis de shell - para bash es el parámetro -c
para leer el script de la cadena:
var spawn = require(''child_process'').spawn;
var shellSyntaxCommand = ''ls -l | grep test | wc -c'';
spawn(''sh'', [''-c'', shellSyntaxCommand], { stdio: ''inherit'' });
Resumir:
var spawn = require(''child_process'').spawn;
function shspawn(command) {
spawn(''sh'', [''-c'', command], { stdio: ''inherit'' });
}
shspawn(''ls -l | grep test | wc -c'');
Puede reemplazar exec
por spawn
y usar la sintaxis de shell simplemente con:
const {spawn} = require (''child_process'');
const cmd = ''ls -l | grep test | wc -c'';
const p = spawn (cmd, [], {shell: true});
p.stdout.on (''data'', (data) => {
console.log (data.toString ());
});
La magia es solo {shell: true}
.