2012-03-19 10 views
43

Sto provando a lanciare un comando shell da Node.js, senza reindirizzare l'input e l'output di quel comando, proprio come eseguire il bombardamento su un comando utilizzando uno script di shell o utilizzando il comando system di Ruby. Se il processo figlio vuole scrivere su STDOUT, voglio che vada direttamente alla console (o venga reindirizzato, se l'output dell'app della Node è stato reindirizzato).Esecuzione di un comando shell da Node.js senza buffer di output

Il nodo non sembra avere un modo semplice per farlo. Sembra che l'unico modo per eseguire un altro processo sia con child_process, che sempre reindirizza l'input e l'output del processo secondario alle pipe. Posso scrivere il codice per accettare i dati da queste pipe e scriverlo su STDOUT e STDERR del mio processo, ma se lo faccio, le API mi costringono a sacrificare un po 'di flessibilità.

Voglio due caratteristiche:

  • sintassi Shell. Voglio essere in grado di convogliare l'output tra i comandi o eseguire file batch di Windows.
  • Uscita illimitata. Se eseguo il bombardamento su un compilatore e desidera generare megabyte di avvisi del compilatore, voglio che tutti scorrano attraverso lo schermo (finché l'utente non si ammala e preme Ctrl + C).

Sembra che Node voglia forzarmi a scegliere tra queste due funzioni.

  • Se voglio una quantità illimitata di uscita, posso usare child_process.spawn e poi fare child.stdout.on('data', function(data) { process.stdout.write(data); }); e la stessa cosa per stderr, e sarà felicemente i dati di tubo fino a quando le mucche tornare a casa. Sfortunatamente, spawn non supporta la sintassi della shell.
  • Se voglio la sintassi della shell, posso usare child_process.exec. Ma exec insiste sul buffering del processo figlio STDOUT e STDERR per me e me li consegna tutti alla fine e limita la dimensione di questi buffer (configurabile, 200K per impostazione predefinita). Posso ancora agganciare gli eventi on('data'), se voglio vedere l'output come è stato generato, ma lo exec aggiungerà ancora i dati ai suoi buffer. Quando la quantità di dati supera la dimensione del buffer predefinita, exec interromperà il processo figlio.

(C'è anche child_process.execFile, che è il peggiore dei due mondi dal punto di vista flessibilità:. Alcuna sintassi shell, ma si devono ancora coronare la quantità di output che ci si aspetta)

mi manca qualcosa? Esiste un modo per eseguire semplicemente lo shell out su un processo figlio nel nodo e non reindirizzare il proprio input e output? Qualcosa che supporta la sintassi della shell e non si espelle dopo una quantità predefinita di output, proprio come è disponibile negli script della shell, in Ruby, ecc.?

+1

Lo hai mai capito? Sono in una situazione simile. –

+0

lo stesso numero, 'fino a quando le mucche tornano a casa' grazie, per questo, ha reso il mio giorno dopo 10 ore di lavoro – neric

risposta

4

non l'ho usato, ma ho visto questa libreria: https://github.com/polotek/procstreams

Ti avrebbe fatto questo. Lo .out() invia automaticamente pipe allo stdin/out del processo.

var $p = require('procstreams'); 
$p('cat lines.txt').pipe('wc -l').out(); 

Se non supporta la sintassi della shell, ma questo è piuttosto banale, penso.

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 
    }); 
+3

ho appena provato, e non supporta i file batch di Windows, che è davvero la ragione principale per cui voglio supporto shell. Un sacco di strumenti originali Unix (ad esempio Rake) sono implementati usando i file batch su Windows e voglio essere in grado di richiamarli dal nodo. –

+0

Cosa intendi con "non supporta"? Si blocca, dice che il file batch non viene trovato, bloccato ed eseguito per sempre? – loganfsmyth

+0

'CreateProcessW: Il sistema non riesce a trovare il file specificato. Lo stesso errore di' child_process.spawn' quando si tenta di eseguire un file batch, perché i file batch non sono eseguibili (direttamente); se provo a lanciare '$ p ('rake'). out();', va alla ricerca di un eseguibile binario chiamato 'rake.exe' o' rake.com', non riesce a trovarli ed errori. È necessaria la shell ('cmd.exe') se si desidera eseguire file batch. –

37

È possibile ereditare flussi stdin/out/errore attraverso spawn argomento in modo non è necessario per il tubo manualmente:

var spawn = require('child_process').spawn; 
spawn('ls', [], { stdio: 'inherit' }); 

Usa shell per la sintassi shell - per bash è -c parametro da leggere script da stringa:

var spawn = require('child_process').spawn; 
var shellSyntaxCommand = 'ls -l | grep test | wc -c'; 
spawn('sh', ['-c', shellSyntaxCommand], { stdio: 'inherit' }); 

Riassumendo:

var spawn = require('child_process').spawn; 
function shspawn(command) { 
    spawn('sh', ['-c', command], { stdio: 'inherit' }); 
} 

shspawn('ls -l | grep test | wc -c'); 
+0

Questo è un po 'più semplice rispetto al dover collegare l'output manualmente, ma ancora non supporta la sintassi della shell. Certo, posso [scegliere manualmente una shell da invocare] (http://stackoverflow.com/a/9779382/87399), ma il mio codice non è multipiattaforma. –

+0

Che '{stdio: 'inherit'}' ha fatto davvero il trucco. Grazie – kabirbaidhya

+0

se vuoi ottenere stdout e stderr, sostituire 'inherit' con 'pipe' – Guig

-1

C'è un esempio nel node docs per il modulo child_process:

Esempio di staccare un processo di lunga durata e riorientare la sua uscita in un file:

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(); 
+2

Come risponde la domanda? Stai mostrando come reindirizzare l'output in un file; la domanda riguardava molto specificamente * non * reindirizzare l'output. –

+0

Penso che tu abbia ragione. Ovviamente ho letto male la domanda la prima volta. Chiedo scusa. – darelf

+1

Questo mi ha aiutato, grazie amico. – Chance

3

È possibile sostituire exec da spawn e l'uso la sintassi shell semplicemente 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 è solo {shell: true}.

Problemi correlati