Выполнение команды оболочки из Node.js без буферизации вывода - PullRequest
49 голосов
/ 20 марта 2012

Я пытаюсь запустить команду оболочки из Node.js, без , перенаправляя ввод и вывод этой команды - так же, как выдает команду, используя сценарий оболочки или 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 дочернего процесса для меня и выдать их мне в конце, и это ограничивает размер этих буферов (настраивается, по умолчанию 200K). Я все еще могу перехватить события on('data'), если я хочу видеть вывод, как он генерируется, но exec все равно добавит данные в свои буферы. Когда объем данных превышает предопределенный размер буфера, exec завершит дочерний процесс.

(Есть также child_process.execFile, что является худшим обоих миров с точки зрения гибкости: нет синтаксиса оболочки, но вам все равно придется ограничить объем ожидаемого результата .)

Я что-то упустил? Есть ли способ просто выполнить оболочку для дочернего процесса в Node, и не перенаправить его ввод и вывод? Что-то, что поддерживает синтаксис оболочки и не выдает после заданного количества вывода, как это доступно в сценариях оболочки, Ruby и т. д .?

Ответы [ 4 ]

41 голосов
/ 14 декабря 2012

Вы можете наследовать потоки stdin / out / error с помощью аргумента spawn, поэтому вам не нужно передавать их вручную:

var spawn = require('child_process').spawn;
spawn('ls', [], { stdio: 'inherit' });

Использовать оболочку для синтаксиса оболочки - для bash это параметр -cпрочитать скрипт из строки:

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');
6 голосов
/ 30 декабря 2016

Вы можете заменить 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 голосов
/ 20 марта 2012

Я не использовал его, но я видел эту библиотеку: https://github.com/polotek/procstreams

Если бы вы сделали это..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
  });
0 голосов
/ 15 марта 2013

В документации по узлу есть пример для модуля 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();
...