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