16

次の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ソースが利用できない、または変更できないと仮定すると、前述の2つのフラッシュオプションのどちらも実装できません。

次に、インタラクティブシェルのエミュレートを検討し始めました。たとえば、次のように、適切に機能する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を使用する方法はありますか?ターミナルエミュレーションまたはプロセススポーンまたはその他の方法のいずれかによって?

乾杯!

4

3 に答える 3

15

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がノードプロセスと効果的に共有されることに注意してください。あなたがそれと一緒に暮らせるかどうかわからない。

于 2013-04-29T14:09:05.873 に答える
5

バージョン5.7.0以降、ノードのspawnコマンドで「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では利用できないようですが、同様の代替手段である可能性があります。

于 2016-03-03T11:15:20.187 に答える
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);

でイベントを使用しstdoutstderrで出力を出力するconsole.logと、関数が非同期で実行されるため、出力が乱雑になります。出力はストリームに対して個別に順序付けられますが、出力は、、、およびの間stdinでインターリーブされる可能性があります。stdoutstderr

于 2013-03-11T18:19:11.683 に答える