Użyj child_process.execSync, ale zachowaj dane wyjściowe w konsoli

160

Chciałbym użyć execSyncmetody, która została dodana w NodeJS 0.12, ale nadal mam dane wyjściowe w oknie konsoli, z którego uruchomiłem skrypt Node.

Np. Jeśli uruchomię skrypt NodeJS, który ma następujący wiersz, chciałbym zobaczyć pełne dane wyjściowe polecenia rsync „na żywo” w konsoli:

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

Rozumiem, że execSynczwraca wynik polecenia i że mógłbym wydrukować to na konsoli po wykonaniu, ale w ten sposób nie mam wyjścia "na żywo" ...

suamikim
źródło

Odpowiedzi:

324

Możesz przekazać stdio rodzica do procesu dziecka, jeśli tego chcesz:

require('child_process').execSync(
    'rsync -avAXz --info=progress2 "/src" "/dest"',
    {stdio: 'inherit'}
);
Gregers
źródło
3
Oznacza to, że proces potomny będzie używał strumieni stdin, stdout i stderr rodzica. Więc kiedy proces potomny zapisze do któregokolwiek z nich, zostanie to faktycznie zapisane bezpośrednio w strumieniu rodzica.
gregers
7
To bardzo cenna odpowiedź, ponieważ oficjalna dokumentacja nie zawiera dokładnych informacji na temat oczekiwanej składni.
chikamichi
49
Zamiast tego [0,1,2]użyłem 'inherit', co jest równoważne [process.stdin, process.stdout, process.stderr]lub [0,1,2]zgodnie z dokumentami
Kurt
10
Prawidłowy link do options.stdiodokumentacji: nodejs.org/api/child_process.html#child_process_options_stdio
Shaun Lebron
2
@Booligoosh Zamiast po prostu dodawać {stdio:'inherit'}, musisz dodać .toString (), a następnie ręcznie wywołać console.log z wynikiem. Ponadto nie spełnia nawet wymogu dotyczącego wyświetlania wyników polecenia „na żywo”. Nie sądzę, że jest to „dużo prostsze”, w rzeczywistości nie sądzę, że jest wcale prostsze.
boileau
19

Możesz po prostu użyć .toString().

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

Zostało to przetestowane na Node v8.5.0, nie jestem pewien co do poprzednich wersji. Według @etov to nie działa v6.3.1- nie jestem pewien co do pomiędzy.

Ethan
źródło
3
To nie działa w przypadku niepowodzenia (kod stanu! = 0), ponieważ .execSync()zgłasza Errorinstancję.
Álvaro González
U mnie nie działa, tzn. Wyjście jest zapisywane dopiero po zakończeniu polecenia. Czy dotyczy to konkretnej wersji? mój węzeł -v: v6.3.1
etov
Rozważ aktualizację odpowiedzi, aby pamiętać, że dotyczy ona tylko niektórych wersji węzłów - dzięki temu będzie bardziej przydatna dla innych
etov
1
Głosuj w dół, ponieważ ti jest teraz w odniesieniu do pytania dotyczącego wyjścia podczas wykonywania polecenia.
karfau
14

O ile nie przekierujesz stdout i stderr, jak sugeruje zaakceptowana odpowiedź, nie jest to możliwe w przypadku execSync lub spawnSync. Bez przekierowywania stdout i stderr te polecenia zwracają stdout i stderr tylko wtedy, gdy polecenie jest zakończone.

Aby to zrobić bez przekierowywania stdout i stderr, będziesz musiał użyć spawn, aby to zrobić, ale jest to całkiem proste:

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

Użyłem polecenia ls, które rekurencyjnie wyświetla listę plików, dzięki czemu można je szybko przetestować. Spawn przyjmuje jako pierwszy argument nazwę pliku wykonywalnego, który próbujesz uruchomić, a jako drugi argument przyjmuje tablicę ciągów reprezentujących każdy parametr, który chcesz przekazać do tego pliku wykonywalnego.

Jeśli jednak korzystasz z execSync iz jakiegoś powodu nie możesz przekierować stdout lub stderr, możesz otworzyć inny terminal, taki jak xterm, i przekazać mu takie polecenie:

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

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

Pozwoli ci to zobaczyć, co robi twoje polecenie w nowym terminalu, ale nadal masz połączenie synchroniczne.

Brian
źródło
2
Przykład użycia spawn może być poprawny, ale stwierdzenie otwierające, że nie zamierzasz używać execSync, nie jest dokładne. Zobacz odpowiedź od @gregers
AgDude,