考虑下面的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时看到的输出非常不同。这是因为当由nodejs生成时,。/ test程序未在交互式外壳中运行。将缓冲test.c stdout流,并且在到达\ n时在终端中运行该缓冲区时,将刷新该缓冲区,但是以这种方式与节点生成时,该缓冲区不会被刷新。可以通过在每次打印后刷新stdout或将stdout流更改为无缓冲的方式来解决,以便立即刷新所有内容。假设test.c源不可用或不可修改,则提到的两个刷新选项都无法实现。
然后,我开始研究模拟交互式外壳,其中有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都合并在一起了(正如您在终端中运行程序时所看到的),我想不出一种将数据与流分离的方法。
所以问题
有没有什么办法可以使用nodejs在不修改test.c代码的情况下实现./test的输出?是通过终端仿真还是通过进程生成或任何其他方法?
干杯!
我只是在重新讨论一下,因为从5.7.0版开始,节点中的spawn命令现在有了一个’shell’选项。不幸的是,似乎没有一个选项可以生成一个 交互式的 shell(我也尝试过shell: '/bin/sh -i'但没有喜悦)。但是,我刚刚发现这建议使用“ stdbuf”,使您可以更改要运行的程序的缓冲选项。将它们在所有内容上都设置为0会为所有流生成无缓冲的输出,并且它们仍然保持分开。
shell: '/bin/sh -i'
这是更新的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也不可用,不过可能是类似的选择。