从Node.js运行没有缓冲输出的shell命令
我试图从Node.js启动shell命令,没有重定向该命令的输入和输出 - 就像使用shell脚本对命令进行脱壳一样,或者使用Ruby的system
命令。如果子进程想要写入STDOUT,我希望直接进入控制台(或者如果我的Node应用程序的输出被重定向,那么会被重定向)。从Node.js运行没有缓冲输出的shell命令
节点似乎没有任何直接的方法来做到这一点。看起来运行另一个进程的唯一方法是使用child_process
,其中总是将子进程的输入和输出重定向到管道。我可以编写代码来接受来自这些管道的数据并将其写入到我的进程的STDOUT和STDERR,但是如果我这样做,这些API迫使我牺牲一些灵活性。
我想两个特点:
- shell语法。我希望能够在命令之间输出输出,或者运行Windows批处理文件。
- 无限输出。如果我正在向编译器发出警告,并且想要生成兆字节的编译器警告,我希望它们全部在屏幕上滚动(直到用户厌倦它并点击Ctrl + C)。
它看起来像节点希望强迫我在这两个功能之间进行选择。
- 如果我想输出无限量的,我可以用
child_process.spawn
,然后stderr
做child.stdout.on('data', function(data) { process.stdout.write(data); });
,同样的事情,它会高兴地管道的数据,直到母牛回家。不幸的是,spawn
不支持shell语法。 - 如果我想要shell语法,我可以使用
child_process.exec
。但exec
坚持为我缓冲子进程的STDOUT和STDERR,并最终将它们全部提供给我,并限制这些缓冲区的大小(可配置,默认为200K)。如果我想查看产生的输出,我仍然可以挂接on('data')
事件,但exec
仍然会将数据添加到其缓冲区。当数据量超过预定义的缓冲区大小时,exec
将终止子进程。
(还有child_process.execFile
,这是从灵活性的角度来看两全其美的最坏:没有shell语法,但你还是要盖你期望的输出量)
我错过什么? 有没有什么办法可以将节点中的子进程掏空,并且而不是重定向它的输入和输出?支持shell语法的东西,并且在预定义的输出量之后不会出现,就像在shell脚本,Ruby等中可用的那样?
我还没有使用它,但我已经看到了这个库: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
});
我只是试过了,它不支持Windows批处理文件,这真的是我想要shell支持的主要原因。很多最初的Unix工具(例如Rake)是在Windows上使用批处理文件实现的,我希望能够从Node中调用它们。 – 2012-03-19 20:45:16
“不支持”是什么意思?它崩溃,说没有找到批处理文件,锁定并永久执行? – loganfsmyth 2012-03-19 20:55:55
'CreateProcessW:系统找不到指定的文件.'当您尝试运行批处理文件时,由于批处理文件不可执行(直接),与'child_process.spawn'错误相同。如果我尝试运行'$ p('rake').out();',它会寻找名为'rake.exe'或'rake.com'的二进制可执行文件,找不到它们,并且出错。如果你想运行批处理文件,你需要shell('cmd.exe')。 – 2012-03-19 21:06:05
您可以通过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');
这比手动输出输出要简单一些,但它仍然不支持shell语法。当然,我可以[手动选择一个shell来调用](http://stackoverflow.com/a/9779382/87399),但我的代码不是跨平台的。 – 2012-12-15 03:30:22
'{stdio:'inherit'}'真的有用。谢谢 – kabirbaidhya 2016-06-30 08:19:31
如果你想得到stdout和stderr,用'pipe'替换'inherit' – Guig 2017-04-17 05:16:15
有一个在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();
您可以通过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());
});
魔术只是{shell: true}
。
你有没有想过这个?我处于类似的情况。 – 2012-11-07 20:18:02
同样的问题,'直到奶牛回家'谢谢,为此,工作10小时后我的一天 – neric 2016-12-22 20:35:59