考虑以下 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
尝试使用以下代码在Node.js中作为子进程生成此程序时:
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`时看到的输出。这是因为当被nodejs生成时,`./test`程序并没有在交互式shell中运行。`test.c`的标准输出流被缓冲,当在终端中运行时,一旦到达`\n`,缓冲区就会被刷新,但是在以这种方式与node一起生成时,缓冲区不会被刷新。这可以通过每次打印后刷新标准输出流,或将标准输出流更改为无缓冲的流来解决。
假设`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被合并在一起(就像在终端中运行程序时看到的那样),我想不到分离数据流的方法。
所以问题是...
有没有办法使用Node.js实现与运行./test相同的输出,而无需修改test.c代码?可以通过终端仿真、进程生成或任何其他方法实现吗?
Cheers!