Verwenden Sie child_process.execSync, behalten Sie jedoch die Ausgabe in der Konsole bei

160

Ich möchte die execSyncMethode verwenden, die in NodeJS 0.12 hinzugefügt wurde, habe aber immer noch die Ausgabe im Konsolenfenster, in dem ich das Node-Skript ausgeführt habe.

Wenn ich beispielsweise ein NodeJS-Skript mit der folgenden Zeile ausführe, möchte ich die vollständige Ausgabe des Befehls rsync "live" in der Konsole sehen:

require('child_process').execSync('rsync -avAXz --info=progress2 "/src" "/dest"');

Ich verstehe, dass dies execSyncdie Ausgabe des Befehls zurückgibt und dass ich diese nach der Ausführung auf die Konsole drucken könnte, aber auf diese Weise habe ich keine "Live" -Ausgabe ...

Suamikim
quelle

Antworten:

324

Sie können das stdio der Eltern an den untergeordneten Prozess übergeben, wenn Sie dies wünschen:

require('child_process').execSync(
    'rsync -avAXz --info=progress2 "/src" "/dest"',
    {stdio: 'inherit'}
);
gregers
quelle
3
Dies bedeutet, dass der untergeordnete Prozess die Streams stdin, stdout und stderr der Eltern verwendet. Wenn also der untergeordnete Prozess in einen von beiden schreibt, wird er tatsächlich direkt in den Stream des übergeordneten Elements geschrieben.
Gregers
7
Dies ist eine sehr wertvolle Antwort, da in der offiziellen Dokumentation die erwartete Syntax nicht wirklich explizit angegeben ist.
Chikamichi
49
Anstelle von [0,1,2]Ich habe verwendet 'inherit', was gleichbedeutend mit [process.stdin, process.stdout, process.stderr]oder [0,1,2]gemäß den Dokumenten ist
Kurt
10
Richtiger Link zur options.stdioDokumentation: nodejs.org/api/child_process.html#child_process_options_stdio
Shaun Lebron
2
@Booligoosh Anstatt einfach hinzuzufügen {stdio:'inherit'}, müssen Sie .toString () hinzufügen und dann console.log manuell mit dem Ergebnis aufrufen. Darüber hinaus erfüllt es nicht einmal die Fragen, die erforderlich sind, um die Befehlsausgabe "live" zu sehen. Ich denke nicht, dass es "viel einfacher" ist, tatsächlich denke ich nicht, dass es überhaupt einfacher ist.
Boileau
19

Sie können einfach verwenden .toString().

var result = require('child_process').execSync('rsync -avAXz --info=progress2 "/src" "/dest"').toString();
console.log(result);

Dies wurde auf Node getestet v8.5.0, ich bin mir bei früheren Versionen nicht sicher. Laut @etov funktioniert es nicht v6.3.1- dazwischen bin ich mir nicht sicher.

Ethan
quelle
3
Dies funktioniert nicht bei einem Fehler (Statuscode! = 0), da .execSync()eine ErrorInstanz ausgelöst wird.
Álvaro González
Funktioniert bei mir nicht, dh die Ausgabe wird erst nach Beendigung des Befehls geschrieben. Gilt das für eine bestimmte Version? mein Knoten -v: v6.3.1
etov
Bitte erwägen Sie, die Antwort zu aktualisieren, um festzustellen, dass sie nur für bestimmte Knotenversionen gilt - dies würde sie für andere nützlicher machen
etov
1
Downvote, da dies jetzt in Bezug auf die Frage bezüglich der Ausgabe während des Befehls geschieht.
karfau
14

Dies ist mit execSync oder spawnSync nicht möglich, es sei denn, Sie leiten stdout und stderr um, wie in der akzeptierten Antwort angegeben. Ohne stdout und stderr umzuleiten, geben diese Befehle stdout und stderr nur zurück, wenn der Befehl abgeschlossen ist.

Um dies zu tun, ohne stdout und stderr umzuleiten, müssen Sie Spawn verwenden, um dies zu tun, aber es ist ziemlich einfach:

var spawn = require('child_process').spawn;

//kick off process of listing files
var child = spawn('ls', ['-l', '/']);

//spit stdout to screen
child.stdout.on('data', function (data) {   process.stdout.write(data.toString());  });

//spit stderr to screen
child.stderr.on('data', function (data) {   process.stdout.write(data.toString());  });

child.on('close', function (code) { 
    console.log("Finished with code " + code);
});

Ich habe einen ls-Befehl verwendet, der Dateien rekursiv auflistet, damit Sie sie schnell testen können. Spawn verwendet als erstes Argument den Namen der ausführbaren Datei, die Sie ausführen möchten, und als zweites Argument ein Array von Zeichenfolgen, die jeden Parameter darstellen, den Sie an diese ausführbare Datei übergeben möchten.

Wenn Sie jedoch auf execSync eingestellt sind und aus irgendeinem Grund stdout oder stderr nicht umleiten können, können Sie ein anderes Terminal wie xterm öffnen und ihm einen Befehl wie den folgenden übergeben:

var execSync = require('child_process').execSync;

execSync("xterm -title RecursiveFileListing -e ls -latkR /");

Auf diese Weise können Sie sehen, was Ihr Befehl im neuen Terminal tut, haben aber dennoch den synchronen Anruf.

Brian
quelle
2
Das Beispiel mit Spawn mag korrekt sein, aber die einleitende Aussage, dass execSync nicht verwendet werden soll, ist nicht korrekt. Siehe Antwort von @gregers
AgDude