简体   繁体   English

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

[英]Running a shell command from Node.js without buffering output

I'm trying to launch a shell command from Node.js, without redirecting that command's input and output -- just like shelling out to a command using a shell script, or using Ruby's system command. 我正在尝试从Node.js启动一个shell命令, 而不重定向该命令的输入和输出 - 就像使用shell脚本弹出命令一样,或者使用Ruby的system命令。 If the child process wants to write to STDOUT, I want that to go straight to the console (or get redirected, if my Node app's output was redirected). 如果子进程想要写入STDOUT,我希望它直接进入控制台(或重定向,如果我的Node应用程序的输出被重定向)。

Node doesn't seem to have any straightforward way to do this. Node似乎没有任何直接的方法来做到这一点。 It looks like the only way to run another process is with child_process , which always redirects the child process's input and output to pipes. 看起来运行另一个进程的唯一方法是使用child_process ,它总是将子进程的输入和输出重定向到管道。 I can write code to accept data from those pipes and write it to my process's STDOUT and STDERR, but if I do that, the APIs force me to sacrifice some flexibility. 我可以编写代码来接受来自这些管道的数据并将其写入我的进程的STDOUT和STDERR,但是如果我这样做,API会迫使我牺牲一些灵活性。

I want two features: 我想要两个功能:

  • Shell syntax. Shell语法。 I want to be able to pipe output between commands, or run Windows batch files. 我希望能够在命令之间管道输出,或运行Windows批处理文件。
  • Unlimited output. 无限输出。 If I'm shelling out to a compiler and it wants to generate megabytes of compiler warnings, I want them all to scroll across the screen (until the user gets sick of it and hits Ctrl+C). 如果我正在向编译器进行shell并且它想要生成兆字节的编译器警告,我希望它们都能在屏幕上滚动(直到用户厌倦了它并按Ctrl + C)。

It looks like Node wants to force me choose between those two features. 看起来Node想强迫我在这两个功能之间做出选择。

  • If I want an unlimited amount of output, I can use child_process.spawn and then do child.stdout.on('data', function(data) { process.stdout.write(data); }); 如果我想要无限量的输出,我可以使用child_process.spawn然后执行child.stdout.on('data', function(data) { process.stdout.write(data); }); and the same thing for stderr , and it'll happily pipe data until the cows come home. 对于stderr同样的事情,它会愉快地管理数据直到奶牛回家。 Unfortunately, spawn doesn't support shell syntax. 不幸的是, spawn不支持shell语法。
  • If I want shell syntax, I can use child_process.exec . 如果我想要shell语法,我可以使用child_process.exec But exec insists on buffering the child process's STDOUT and STDERR for me and giving them to me all at the end, and it limits the size of those buffers (configurable, 200K by default). 但是exec坚持为我缓冲子进程的STDOUT和STDERR并最终将它们交给我,并且它限制了这些缓冲区的大小(可配置,默认为200K)。 I can still hook the on('data') events, if I want to see the output as it's generated, but exec will still add the data to its buffers too. 我仍然可以挂钩on('data')事件,如果我想看到生成的输出,但exec仍然会将数据添加到它的缓冲区。 When the amount of data exceeds the predefined buffer size, exec will terminate the child process. 当数据量超过预定义的缓冲区大小时, exec将终止子进程。

(There's also child_process.execFile , which is the worst of both worlds from a flexibility standpoint: no shell syntax, but you still have to cap the amount of output you expect.) (还有child_process.execFile ,从灵活性的角度来看,这是两个世界中最糟糕的:没有shell语法,但你仍然需要限制你期望的输出量。)

Am I missing something? 我错过了什么吗? Is there any way to just shell out to a child process in Node, and not redirect its input and output? 有没有办法在Node中弹出子进程,而不是重定向其输入和输出? Something that supports shell syntax and doesn't crap out after a predefined amount of output, just like is available in shell scripts, Ruby, etc.? 支持shell语法并且在预定义的输出量之后不会丢失的东西,就像在shell脚本,Ruby等中可用的那样?

You can inherit stdin/out/error streams via spawn argument so you don't need to pipe them manually: 您可以通过spawn参数继承stdin / out / error流,因此您不需要手动管道它们:

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

Use shell for shell syntax - for bash it's -c parameter to read script from string: 使用shell进行shell语法 - 对于bash它是-c参数从字符串中读取脚本:

var spawn = require('child_process').spawn;
var shellSyntaxCommand = 'ls -l | grep test | wc -c';
spawn('sh', ['-c', shellSyntaxCommand], { stdio: 'inherit' });

To summarise: 总结一下:

var spawn = require('child_process').spawn;
function shspawn(command) {
   spawn('sh', ['-c', command], { stdio: 'inherit' });
} 

shspawn('ls -l | grep test | wc -c');

You can replace exec by spawn and use the shell syntax simply with: 您可以通过spawn替换exec并使用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 ());
});

The magic is just {shell: true} . 神奇的只是{shell: true}

I haven't used it, but I've seen this library: https://github.com/polotek/procstreams 我没有用它,但我见过这个库: https//github.com/polotek/procstreams

It you'd do this. 你做到了这一点。 The .out() automatically pipes to the process's stdin/out. .out()自动管道进程的stdin / out。

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

If doesn't support shell syntax, but that's pretty trivial I think. 如果不支持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
  });

There's an example in the node docs for the child_process module: child_process模块​​的节点文档中有一个示例:

Example of detaching a long-running process and redirecting its output to a file: 分离长时间运行的进程并将其输出重定向到文件的示例:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM