web-dev-qa-db-fra.com

Exec: affiche stdout "live"

J'ai ce script simple:

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

exec('coffee -cw my_file.coffee', function(error, stdout, stderr) {
    console.log(stdout);
});

où j'exécute simplement une commande pour compiler un fichier de script de café. Mais stdout ne sera jamais affiché dans la console, car la commande ne se termine jamais (à cause de l'option -w de coffee). Si j'exécute la commande directement à partir de la console, le message suivant s'affiche:

18:05:59 - compiled my_file.coffee

Ma question est: est-il possible d'afficher ces messages avec le noeud exec.js? Si oui comment? !

Merci

146
TrexXx

N'utilisez pas exec. Utilisez spawn qui est un objet EventEmmiter. Ensuite, vous pouvez écouter les événements stdout/stderr (spawn.stdout.on('data',callback..)) tels qu'ils se produisent .

À partir de la documentation NodeJS:

var spawn = require('child_process').spawn,
    ls    = spawn('ls', ['-lh', '/usr']);

ls.stdout.on('data', function (data) {
  console.log('stdout: ' + data.toString());
});

ls.stderr.on('data', function (data) {
  console.log('stderr: ' + data.toString());
});

ls.on('exit', function (code) {
  console.log('child process exited with code ' + code.toString());
});

exec met la sortie en mémoire tampon et la renvoie généralement à la fin de l'exécution de la commande.

225
Pooria Azimi

exec renverra également un objet ChildProcess qui est un EventEmitter.

var exec = require('child_process').exec;
var coffeeProcess = exec('coffee -cw my_file.coffee');

coffeeProcess.stdout.on('data', function(data) {
    console.log(data); 
});

OU pipe la sortie standard du processus enfant vers la sortie principale.

coffeeProcess.stdout.pipe(process.stdout);

OU hériter de stdio en utilisant spawn

spawn('coffee -cw my_file.coffee', { stdio: 'inherit' });
142
Nathanael Smith

Il existe déjà plusieurs réponses, mais aucune d’entre elles ne mentionne la meilleure (et la plus simple) façon de le faire, qui utilise spawn et le { stdio: 'inherit' } option . Il semble produire la sortie la plus précise, par exemple lors de l’affichage des informations de progression d’un git clone.

Faites simplement ceci:

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

spawn('coffee', ['-cw', 'my_file.coffee'], { stdio: 'inherit' });

Nous remercions @MorganTouvereyQuilling de l'avoir signalé dans ce commentaire .

40
Livven

J'aimerais simplement ajouter qu'un petit problème avec la sortie des chaînes de mémoire tampon d'un processus généré avec console.log() est qu'il ajoute des nouvelles lignes, ce qui peut étendre la sortie de votre processus généré sur des lignes supplémentaires. Si vous exportez stdout ou stderr avec process.stdout.write() au lieu de console.log(), vous obtiendrez la sortie de la console du processus généré 'en l'état' .

J'ai vu cette solution ici: Node.js: imprimer sur console sans nouvelle ligne?

J'espère que cela aidera quelqu'un qui utilise la solution ci-dessus (ce qui est excellent pour les sorties en direct, même si cela provient de la documentation).

21
Kevin Teljeur

Inspiré par la réponse de Nathanael Smith et le commentaire d'Eric Freese, cela pourrait être aussi simple que:

var exec = require('child_process').exec;
exec('coffee -cw my_file.coffee').stdout.pipe(process.stdout);
16
Tyler Long

J'ai trouvé utile d'ajouter un script d'exécution personnalisé à mes utilitaires qui effectuent cette opération.

utilities.js

const { exec } = require('child_process')

module.exports.exec = (command) => {
  const process = exec(command)

  process.stdout.on('data', (data) => {
    console.log('stdout: ' + data.toString())
  })

  process.stderr.on('data', (data) => {
    console.log('stderr: ' + data.toString())
  })

  process.on('exit', (code) => {
    console.log('child process exited with code ' + code.toString())
  })
}

app.js

const { exec } = require('./utilities.js')

exec('coffee -cw my_file.coffee')
7
IanLancaster

Après avoir examiné toutes les autres réponses, je me suis retrouvé avec ceci:

function oldSchoolMakeBuild(cb) {
    var makeProcess = exec('make -C ./oldSchoolMakeBuild',
         function (error, stdout, stderr) {
             stderr && console.error(stderr);
             cb(error);
        });
    makeProcess.stdout.on('data', function(data) {
        process.stdout.write('oldSchoolMakeBuild: '+ data);
    });
}

Parfois, data aura plusieurs lignes. L'en-tête oldSchoolMakeBuild apparaît alors une fois pour plusieurs lignes. Mais cela ne m'a pas dérangé assez pour le changer.

4
Tongfa

child_process.spawn renvoie un objet avec les flux stdout et stderr. Vous pouvez appuyer sur le flux stdout pour lire les données que le processus enfant renvoie au nœud. stdout étant un flux, les événements "data", "end" et autres sont présents. spawn est mieux utilisé lorsque vous souhaitez que le processus enfant renvoie une grande quantité de données à Node - traitement d'image, lecture de données binaires, etc.).

afin que vous puissiez résoudre votre problème en utilisant child_process.spawn comme utilisé ci-dessous.

var spawn = require('child_process').spawn,
ls = spawn('coffee -cw my_file.coffee');

ls.stdout.on('data', function (data) {
  console.log('stdout: ' + data.toString());
});

ls.stderr.on('data', function (data) {
  console.log('stderr: ' + data.toString());
});

ls.on('exit', function (code) {
  console.log('code ' + code.toString());
});
1