Запуск команды оболочки из Node.js без вывода буферизации
Я пытаюсь запустить команду оболочки из Node.js, не перенаправляя ввод и вывод этой команды - так же, как обход команды с помощью оболочки script или с помощью команды Ruby system
. Если дочерний процесс хочет записать в STDOUT, я хочу, чтобы он перешел прямо в консоль (или перенаправлялся, если мой выход Node был перенаправлен).
Node, похоже, не имеет прямого способа сделать это. Похоже, что единственный способ запустить другой процесс - это child_process
, который всегда перенаправляет входной сигнал дочернего процесса и выводит его на трубы. Я могу написать код для приема данных из этих каналов и записать его в мой процесс STDOUT и STDERR, но если я это сделаю, API-интерфейсы заставят меня пожертвовать некоторой гибкостью.
Я хочу две функции:
- Синтаксис оболочки. Я хочу иметь возможность выводить выходные данные между командами или запускать командные файлы Windows.
- Неограниченный вывод. Если я обманываю компилятор и хочу генерировать мегабайты предупреждений компилятора, я хочу, чтобы они все прокручивали экран (пока пользователь не заболел и не нажал Ctrl + C).
Похоже, что Node хочет заставить меня выбирать между этими двумя функциями.
- Если я хочу неограниченное количество вывода, я могу использовать
child_process.spawn
, а затем сделать child.stdout.on('data', function(data) { process.stdout.write(data); });
и то же самое для stderr
, и это" Будем счастливо передавать данные, пока коровы не вернутся домой. К сожалению, spawn
не поддерживает синтаксис оболочки.
- Если мне нужен синтаксис оболочки, я могу использовать
child_process.exec
. Но exec
настаивает на буферизации дочернего процесса STDOUT и STDERR для меня и предоставления им всех в конце и ограничивает размер этих буферов (настраивается, по умолчанию 200 КБ). Я все еще могу подключить события on('data')
, если я хочу видеть результат по мере его создания, но exec
все равно добавит данные в свои буферы. Когда количество данных превышает предопределенный размер буфера, exec
завершает дочерний процесс.
(Там также child_process.execFile
, который является наихудшим из обоих миров с точки зрения гибкости: без синтаксиса оболочки, но вам все равно нужно ограничить объем вывода вы ожидаете.)
Я что-то упустил? Есть ли способ просто выложить на дочерний процесс в Node, а не перенаправлять его ввод и вывод? Что-то, что поддерживает синтаксис оболочки и не дерьмово после предопределенного объема вывода, как и в сценариях оболочки, Ruby и т.д.
Ответы
Ответ 1
Вы можете наследовать потоки stdin/out/error с помощью аргумента spawn
, поэтому вам не нужно их вручную связывать:
var spawn = require('child_process').spawn;
spawn('ls', [], { stdio: 'inherit' });
Использовать оболочку для синтаксиса оболочки - для параметра bash it -c
для чтения script из строки:
var spawn = require('child_process').spawn;
var shellSyntaxCommand = 'ls -l | grep test | wc -c';
spawn('sh', ['-c', shellSyntaxCommand], { stdio: 'inherit' });
Подводя итог:
var spawn = require('child_process').spawn;
function shspawn(command) {
spawn('sh', ['-c', command], { stdio: 'inherit' });
}
shspawn('ls -l | grep test | wc -c');
Ответ 2
Я не использовал его, но я видел эту библиотеку: https://github.com/polotek/procstreams
Это вы сделали бы. .out()
автоматически подключается к процессу stdin/out.
var $p = require('procstreams');
$p('cat lines.txt').pipe('wc -l').out();
Если не поддерживается синтаксис оболочки, но это довольно тривиально, я думаю.
var command_str = "cat lines.txt | wc -l";
var cmds = command_str.split(/\s?\|\s?/);
var cmd = $p(cmds.shift());
while(cmds.length) cmd = cmd.pipe(cmds.shift());
cmd
.out()
.on('exit', function() {
// Do whatever
});
Ответ 3
Вы можете заменить exec
на spawn
и использовать синтаксис оболочки просто с помощью
const {spawn} = require ('child_process');
const cmd = 'ls -l | grep test | wc -c';
const p = spawn (cmd, [], {shell: true});
p.stdout.on ('data', (data) => {
console.log (data.toString ());
});
Магия - это просто {shell: true}
.
Ответ 4
Вот пример в node docs для модуля child_process:
Пример отсоединения долговременного процесса и перенаправление его вывода в файл:
var fs = require('fs'),
spawn = require('child_process').spawn,
out = fs.openSync('./out.log', 'a'),
err = fs.openSync('./out.log', 'a');
var child = spawn('prg', [], {
detached: true,
stdio: [ 'ignore', out, err ]
});
child.unref();