簡體   English   中英

Node.js使用單獨的stdout和stderr流以交互方式生成子進程

[英]Node.js spawning a child process interactively with separate stdout and stderr streams

考慮以下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都合並在一起(正如你在終端中運行程序時所看到的那樣),我想不出將數據與流分離的方法。

所以問題..

有沒有辦法使用nodejs來實現輸出,就像在運行./test而不修改test.c代碼時看到的那樣? 通過終端仿真或流程產生或任何其他方法?

干杯!

我嘗試了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。 不確定你是否可以忍受。

我只是重新審視這個,因為自5.7.0版以來,節點中的spawn命令現在有一個“shell”選項。 不幸的是,似乎沒有選擇產生交互式 shell(我也試過shell: '/bin/sh -i'但沒有歡樂)。 但是我剛發現這個建議使用'stdbuf'允許你改變你想要運行的程序的緩沖選項。 在所有內容中將它們設置為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,但可能是類似的替代方案。

你可以這樣做 :

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

當您在stdoutstderr上使用事件來在console.log上打印輸出時,由於函數的異步執行,您將得到混亂的輸出。 輸出將獨立地為流排序,但輸出仍然可以在stdinstdoutstderr之間交錯。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM