Подтвердить что ты не робот

Запуск команды оболочки из 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 и т.д.

4b9b3361

Ответ 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();