57

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

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

我想要两个功能:

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

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

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

(还有child_process.execFile,从灵活性的角度来看,这是两全其美的:没有 shell 语法,但你仍然必须限制你期望的输出量。)

我错过了什么吗?有什么方法可以只在 Node 中的子进程中使用,而不是重定向它的输入和输出?支持 shell 语法并且在预定义数量的输出后不会出错的东西,就像在 shell 脚本、Ruby 等中可用的那样?

4

4 回答 4

46

您可以通过参数继承标准输入/输出/错误流,spawn因此您不需要手动管道它们:

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');
于 2012-12-14T13:24:02.847 回答
14

您可以简单地替换execspawn使用 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}

于 2016-12-30T17:34:30.227 回答
4

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

你会这样做。.out()自动管道到进程的标准输入/输出。

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

If 不支持 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
  });
于 2012-03-19T20:39:25.253 回答
0

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();
于 2013-03-15T15:50:49.950 回答