Utilisez child_process.execSync mais conservez la sortie dans la console

160

Je voudrais utiliser la execSyncméthode qui a été ajoutée dans NodeJS 0.12 mais j'ai toujours la sortie dans la fenêtre de la console à partir de laquelle j'ai exécuté le script Node.

Par exemple, si j'exécute un script NodeJS qui a la ligne suivante, j'aimerais voir la sortie complète de la commande rsync "live" dans la console:

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

Je comprends que execSyncrenvoie la sortie de la commande et que je pourrais l'imprimer sur la console après l'exécution mais de cette façon je n'ai pas de sortie "live" ...

suamikim
la source

Réponses:

324

Vous pouvez transmettre le stdio du parent au processus enfant si c'est ce que vous voulez:

require('child_process').execSync(
    'rsync -avAXz --info=progress2 "/src" "/dest"',
    {stdio: 'inherit'}
);
grégeurs
la source
3
Cela signifie que le processus enfant utilisera les flux stdin, stdout et stderr du parent. Ainsi, lorsque le processus enfant écrit sur l'un ou l'autre, il sera en fait écrit directement dans le flux du parent.
gregers
7
C'est une réponse très précieuse, car la documentation officielle n'est pas vraiment explicite sur la syntaxe attendue.
chikamichi
49
Au lieu de [0,1,2]j'ai utilisé 'inherit', ce qui équivaut à [process.stdin, process.stdout, process.stderr]ou [0,1,2]selon les documents
Kurt
10
Lien correct vers la options.stdiodocumentation: nodejs.org/api/child_process.html#child_process_options_stdio
Shaun Lebron
2
@Booligoosh Au lieu d'ajouter simplement {stdio:'inherit'}, vous devez ajouter .toString () puis appeler console.log manuellement avec le résultat. De plus, il ne répond même pas à l'exigence de voir la sortie de la commande "en direct". Je ne pense pas que ce soit "beaucoup plus simple", en fait je ne pense pas que ce soit plus simple du tout.
boileau
19

Vous pouvez simplement utiliser .toString().

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

Cela a été testé sur Node v8.5.0, je ne suis pas sûr des versions précédentes. Selon @etov , cela ne fonctionne pas v6.3.1- je ne suis pas sûr de l'intervalle.

Ethan
la source
3
Cela ne fonctionne pas en cas d'échec (code d'état! = 0) car il .execSync()lance une Errorinstance.
Álvaro González
Cela ne fonctionne pas pour moi, c'est à dire que la sortie n'est écrite qu'après la fin de la commande. Cela s'applique-t-il à une version spécifique? mon nœud -v: v6.3.1
etov
Veuillez envisager de mettre à jour la réponse pour noter qu'elle ne s'applique qu'à certaines versions de nœuds - cela la rendrait plus utile pour d'autres
etov
1
Downvote puisque ti est maintenant lié à la question concernant la sortie pendant la commande est exécutée.
karfau le
14

À moins que vous ne redirigiez stdout et stderr comme le suggère la réponse acceptée, cela n'est pas possible avec execSync ou spawnSync. Sans rediriger stdout et stderr, ces commandes ne renvoient stdout et stderr que lorsque la commande est terminée.

Pour ce faire sans rediriger stdout et stderr, vous devrez utiliser spawn pour le faire, mais c'est assez simple:

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

J'ai utilisé une commande ls qui répertorie les fichiers de manière récursive afin que vous puissiez le tester rapidement. Spawn prend comme premier argument le nom de l'exécutable que vous essayez d'exécuter et comme deuxième argument, il prend un tableau de chaînes représentant chaque paramètre que vous voulez passer à cet exécutable.

Cependant, si vous êtes configuré pour utiliser execSync et que vous ne pouvez pas rediriger stdout ou stderr pour une raison quelconque, vous pouvez ouvrir un autre terminal comme xterm et lui passer une commande comme ceci:

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

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

Cela vous permettra de voir ce que fait votre commande dans le nouveau terminal tout en conservant l'appel synchrone.

Brian
la source
2
L'exemple utilisant spawn peut être correct, mais la déclaration d'ouverture sur le fait de ne pas être sur le point d'utiliser execSync n'est pas exacte. Voir la réponse de @gregers
AgDude