Exec: отображение stdout "live"

У меня есть этот простой script:

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

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

где я просто выполняю команду для компиляции файла coffee- script. Но stdout никогда не отображается в консоли, потому что команда никогда не заканчивается (из-за опции -w кофе). Если я выполню команду непосредственно с консоли, я получаю сообщение следующим образом:

18:05:59 - compiled my_file.coffee

Мой вопрос: можно ли отображать эти сообщения с помощью node.js exec? Если да, то как?

Спасибо

Ответ 1

Не используйте exec. Используйте spawn, который является объектом EventEmmiter. Затем вы можете слушать события stdout/stderr (spawn.stdout.on('data',callback..)) по мере их возникновения.

Из документации 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 буферизует вывод и обычно возвращает его, когда команда завершила выполнение.

Ответ 2

exec также вернет объект ChildProcess, который является EventEmitter.

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

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

ИЛИ pipe дочерний стандартный процесс stdout в основной стандартный вывод.

coffeeProcess.stdout.pipe(process.stdout);

ИЛИ наследовать stdio с помощью spawn

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

Ответ 3

Есть уже несколько ответов, однако ни один из них не упоминает лучший (и самый простой) способ сделать это, используя spawn и { stdio: 'inherit' } вариант. Кажется, он производит наиболее точный вывод, например, при отображении информации о ходе от git clone.

Просто выполните следующее:

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

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

Кредит @MorganTouvereyQuilling для указания этого в этом комментарии.

Ответ 4

Я хотел бы добавить, что одна небольшая проблема с выдачей строк буфера из порожденного процесса с console.log() заключается в том, что он добавляет новые строки, которые могут распространять ваш обработанный процесс на дополнительные строки. Если вы выведете stdout или stderr с помощью process.stdout.write() вместо console.log(), вы получите вывод консоли из порожденного процесса "как есть".

Я видел это решение здесь: Node.js: печать на консоль без завершающей новой строки?

Надеюсь, что это поможет кому-то, использующему вышеприведенное решение (которое отлично подходит для живого выхода, даже если оно из документации).

Ответ 5

Вдохновленный ответом Нафанаила Смита и комментарием Эрика Фриза, это может быть так же просто, как:

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

Ответ 6

После просмотра всех других ответов я закончил с этим:

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

Иногда data будет несколько строк, поэтому заголовок oldSchoolMakeBuild появится один раз для нескольких строк. Но это меня не беспокоило, чтобы изменить его.

Ответ 7

Я нашел полезным добавить пользовательский exec script к моим утилитам, которые это делают.

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')

Ответ 8

child_process.spawn возвращает объект с потоками stdout и stderr. Вы можете нажать на поток stdout, чтобы прочитать данные, которые дочерний процесс отправляет обратно в Node. stdout, являющийся потоком, имеет "данные", "конец" и другие события, которые имеют потоки. spawn лучше всего использовать, когда вы хотите, чтобы дочерний процесс возвращал большой объем данных в Node - обработка изображений, чтение двоичных данных и т.д.

так что вы можете решить вашу проблему, используя child_process.spawn, как показано ниже.

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