考虑以下C程序(test.c):
#include <stdio.h>
int main() {
printf("string out 1\n");
fprintf(stderr, "string err 1\n");
getchar();
printf("string out 2\n");
fprintf(stderr, "string err 2\n");
fclose(stdout);
}
哪一行应该打印一行到stdout,一行到stderr,然后等待用户输入,然后另一行到stdout,另一行到stderr。非常基本! 在编译并在命令行上运行时,程序输出完成后(收到getchar()的用户输入):
$ ./test
string out 1
string err 1
string out 2
string err 2
当尝试使用带有以下代码的nodejs将此程序生成为子进程时:
var TEST_EXEC = './test';
var spawn = require('child_process').spawn;
var test = spawn(TEST_EXEC);
test.stdout.on('data', function (data) {
console.log('stdout: ' + data);
});
test.stderr.on('data', function (data) {
console.log('stderr: ' + data);
});
// Simulate entering data for getchar() after 1 second
setTimeout(function() {
test.stdin.write('\n');
}, 1000);
输出如下所示:
$ nodejs test.js
stderr: string err 1
stdout: string out 1
string out 2
stderr: string err 2
与在终端中运行./test时看到的输出非常不同。这是因为./test程序在由nodejs生成时没有在交互式shell中运行。 test.c stdout流被缓冲,当到达\ n时在终端中运行时,刷新缓冲区,但是当以这种方式生成缓冲区时,缓冲区不会被刷新。这可以通过在每次打印后刷新stdout,或者将stdout流更改为无缓冲来解决,以便立即刷新所有内容。 假设test.c源不可用或不可修改,则所提到的两个刷新选项都不能实现。
然后我开始考虑模拟交互式shell,pty.js(伪终端)做得很好,例如:
var spawn = require('pty.js').spawn;
var test = spawn(TEST_EXEC);
test.on('data', function (data) {
console.log('data: ' + data);
});
// Simulate entering data for getchar() after 1 second
setTimeout(function() {
test.write('\n');
}, 1000);
哪个输出:
$ nodejs test.js
data: string out 1
string err 1
data:
data: string out 2
string err 2
然而,stdout和stderr都被合并在一起(正如你在终端中运行程序时所看到的那样),我想不出将数据与流分离的方法。
所以问题......
在没有修改test.c代码的情况下运行./test时是否有任何方法可以使用nodejs来实现输出?通过终端仿真或流程产生或任何其他方法?
干杯!
答案 0 :(得分:11)
我尝试了user568109的答案,但这不起作用,这是有道理的,因为管道只在流之间复制数据。因此,只有在刷新缓冲区时才会进入process.stdout ... 以下似乎有效:
var TEST_EXEC = './test';
var spawn = require('child_process').spawn;
var test = spawn(TEST_EXEC, [], { stdio: 'inherit' });
//the following is unfortunately not working
//test.stdout.on('data', function (data) {
// console.log('stdout: ' + data);
//});
请注意,这有效地与节点进程共享stdio。不确定你是否可以忍受。
答案 1 :(得分:3)
我刚刚重访这个,因为现在有一个&#39; shell&#39;自5.7.0版以来,节点中的spawn命令可用的选项。不幸的是,似乎没有选择产生一个交互式 shell(我也试过shell: '/bin/sh -i'
但没有欢乐)。
但是我刚发现this建议使用&#39; stdbuf&#39;允许您更改要运行的程序的缓冲选项。在所有内容中将它们设置为0会为所有流生成无缓冲输出,并且它们仍然保持独立。
这是更新的javascript:
var TEST_EXEC = './test';
var spawn = require('child_process').spawn;
var test = spawn('stdbuf', ['-i0', '-o0', '-e0', TEST_EXEC]);
test.stdout.on('data', function (data) {
console.log('stdout: ' + data);
});
test.stderr.on('data', function (data) {
console.log('stderr: ' + data);
});
// Simulate entering data for getchar() after 1 second
setTimeout(function() {
test.stdin.write('\n');
}, 1000);
看起来这并没有预先安装在OSX上,当然不适用于Windows,但可能是类似的替代方案。
答案 2 :(得分:2)
你可以这样做:
var TEST_EXEC = 'test';
var spawn = require('child_process').spawn;
var test = spawn(TEST_EXEC);
test.stdin.pipe(process.stdin);
test.stdout.pipe(process.stdout);
test.stderr.pipe(process.stderr);
当您使用stdout
和stderr
上的事件在console.log
上打印输出时,由于函数的异步执行,您将得到混乱的输出。输出将独立地为流排序,但输出仍然可以在stdin
,stdout
和stderr
之间进行交错。