从Node.js运行shell命令而不缓冲输出

时间:2012-03-19 20:13:29

标签: node.js child-process

我正在尝试从Node.js启动一个shell命令,没有重定向该命令的输入和输出 - 就像使用shell脚本弹出命令一样,或者使用Ruby的{{ 1}}命令。如果子进程想要写入STDOUT,我希望它直接进入控制台(或重定向,如果我的Node应用程序的输出被重定向)。

Node似乎没有任何直接的方法来执行此操作。看起来运行另一个进程的唯一方法是使用system始终将子进程的输入和输出重定向到管道。我可以编写代码来接受来自这些管道的数据并将其写入我的进程的STDOUT和STDERR,但是如果我这样做,API会迫使我牺牲一些灵活性。

我想要两个功能:

  • Shell语法。我希望能够在命令之间管道输出,或运行Windows批处理文件。
  • 无限输出。如果我正在向编译器发出攻击并希望生成兆字节的编译器警告,我希望它们都能在屏幕上滚动(直到用户厌倦了它并按Ctrl + C)。

看起来Node想强迫我在这两个功能之间做出选择。

  • 如果我想要无限量的输出,我可以使用child_process.spawn,然后对child_process执行child.stdout.on('data', function(data) { process.stdout.write(data); });和同样的事情,并且它会愉快地管理数据直到奶牛来家。不幸的是,stderr不支持shell语法。
  • 如果我想要shell语法,我可以使用child_process.exec。但是spawn坚持为我缓冲子进程的STDOUT和STDERR并在最后将它们全部交给我,并且它限制了这些缓冲区的大小(可配置,默认为200K)。我仍然可以挂钩exec事件,如果我想看到生成的输出,但on('data')仍会将数据添加到其缓冲区。当数据量超过预定义的缓冲区大小时,exec将终止子进程。

(还有child_process.execFile,从灵活性的角度来看,这两个世界的最差:没有shell语法,但你仍然需要限制你期望的输出量。)< / p>

我错过了什么吗? 有没有办法在Node中弹出子进程,而重定向其输入和输出?支持shell语法的东西,并且不会在预定义的输出量,就像在shell脚本,Ruby等中可用的那样?

4 个答案:

答案 0 :(得分:41)

您可以通过spawn参数继承stdin / out / error流,这样您就不需要手动管道它们了:

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

使用shell进行shell语法 - 对于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');

答案 1 :(得分:5)

您可以将exec替换为spawn,并将shell语法简单地用于:

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}

答案 2 :(得分:4)

我没有使用它,但我看过这个库:https://github.com/polotek/procstreams

你会这样做。 .out()自动管道进程的stdin / out。

var $p = require('procstreams');
$p('cat lines.txt').pipe('wc -l').out();

如果不支持shell语法,但我认为这非常简单。

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 :(得分:0)

child_process模块​​的node docs中有一个例子:

分离长时间运行的进程并将其输出重定向到文件的示例:

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