2013-03-11 5 views
12

다음 C 프로그램 (TEST.C) 고려 스트림 : 표준 출력 할 수있는 선을 인쇄해야Node.js를가

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

는, 라인이 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); 

출력은 다음과 같이 나타난다 :

termina에 ./test를 실행하는 경우와 같이 출력과 매우 상이한
$ nodejs test.js 
stderr: string err 1 

stdout: string out 1 
string out 2 

stderr: string err 2 

엘. 이것은 ./test 프로그램이 nodejs에 의해 생성 될 때 대화식 쉘에서 실행되지 않기 때문입니다. test.c stdout 스트림은 버퍼링되며 \ n에 도달하자 마자 터미널에서 실행될 때 버퍼는 플러시되지만 노드와 함께 이런 방식으로 생성 될 때 버퍼는 플러시되지 않습니다. 이것은 모든 인쇄 후에 표준 출력을 플러시하거나 표준 출력 스트림을 버퍼링하지 않도록 변경하여 모든 것을 즉시 플러시 할 수 있습니다. test.c 소스를 사용할 수 없거나 수정할 수 없다고 가정하면 언급 된 두 가지 플러싱 옵션 중 어느 것도 구현할 수 없습니다.

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 

그러나 모두

나는 다음 예를 들어, 좋은 일을 pty.js (가상 터미널)있다, 대화 형 쉘을 모방보고 시작 stdout과 stderr는 함께 병합됩니다 (터미널에서 프로그램을 실행할 때 알 수 있듯이) 나는 스트림에서 데이터를 분리하는 방법을 생각할 수 없습니다.

그래서 질문 ..

는 TEST.C 코드를 수정하지 않고 ./test 실행할 때와 같이 출력을 달성하기 위해 nodejs를 사용하는 방법이 있습니까? 터미널 에뮬레이션이나 프로세스 스폰 또는 다른 방법을 사용합니까?

건배!

+0

문제 설명에 많은 노력을 쏟아 주셔서 감사합니다! 노드 내에서 다른 사람의 파이썬 스크립트를 실행할 때도 같은 문제가 있었지만 기본 버퍼링 메커니즘에 대해서는 알지 못했습니다. 분명히 (내 파이썬 기술은 +/- 존재하지 않음) 단순히 'python -u'를 사용하면 언 버퍼 드 IO를 활성화하고 내 문제를 해결할 수 있습니다! – Matthias

+0

@gratz이 문제를 해결 했습니까? 나는 비슷한 문제에 직면하고있다. http://stackoverflow.com/questions/42130677/how-to-get-mongo-shell-outputthree-dot-for-unterminated-command –

답변

2

버전 5.7.0 이후에 노드에있는 spawn 명령에 '셸'옵션을 사용할 수 있으므로 지금 다시 살펴 보았습니다. 불행히도 대화 형 쉘 (나는 또한 shell: '/bin/sh -i'으로 시도했지만 기쁨 없음)을 생성하는 옵션이없는 것 같습니다. 그러나 나는 방금 실행하려는 프로그램의 버퍼링 옵션을 변경할 수 있도록 'stdbuf'를 사용하는 것이 좋습니다 this을 발견했습니다. 모든 값을 0으로 설정하면 모든 스트림에 대해 버퍼링되지 않은 출력이 생성되며 여전히 분리되어 있습니다. 하지만 비슷한 대안이 될 수있다, 이것은 OSX와 Windows 용 사용할 수 없습니다 물론 사전 설치되어 있지 않은 것처럼

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

가 보이는 :

여기에 업데이트 된 자바 스크립트입니다.

+1

'stdbuf'트릭이 해결했습니다. 문제는 내가 (Raspbian Jessie에 대한 노드 v0.10.29를 사용하여) 생성 된 셸 내부에서 실행중인 명령의 표준 버퍼링 문제였습니다. 감사합니다. gratz! – mvanallen

+0

Glad this helped @mvanallen – gratz

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

당신이 console.log에 출력을 인쇄 할 수 stdoutstderr 이벤트를 사용

, 당신 때문에 함수의 비동기 실행의 뒤죽박죽 출력을 얻을 것이다. 출력은 스트림에 대해 독립적으로 정렬되지만, 출력은 여전히 ​​ stdin, stdoutstderr 사이에서 인터리브됩니다.

+0

내가 놓친 것이 아니라면 어떻게하면 프로그래밍 방식으로 출력을 사용할 수 있습니까? 이런 식으로? – gratz

+0

'test'의 표준 스트림을 다른 프로세스라고하는 프로세스 'a'(여기서는 노드 자체)로 파이프 할 수 있습니다. 출력은 테스트의 출력을 수신하기 위해 코드를 사용하면서 'test'의 출력이됩니다. – user568109

+0

하지만 '\ n'에 도달했을 때 stdout을 얻으려면 테스트 파이프가 대화 형 셸에서 실행되는 것처럼 플러시되도록 프로세스가 터미널 또는 의사 터미널 (pty)이어야합니다. 위의 예와 같이 stdout과 stderr의 차이를 잃어 버리는 것을 의미합니까? – gratz

11

나는이 답변을 user568109에 의해 시도했지만이 방법은 효과가 없습니다. 파이프가 스트림간에 데이터를 복사하기 때문에 의미가 있습니다. 따라서 버퍼가 플러시 될 때만 처리 할 수 ​​있습니다 .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); 
//}); 

하는 것으로. 네가 그걸로 살 수 있을지 모르겠다.

+1

'{stdio : 'inherit'}'은 부모 스트림에 인터리브 된 출력을 가능하게하지만 실제로는 적어도 0.10.10으로 ** 이벤트를 통해 스트림에서 "수신 대기"할 수있는 능력을 상실합니다 ** : 자식 프로세스 객체의'.stdin','.stdout','.stderr' 속성을 수정하십시오 : "자식 stdio 스트림이 부모와 공유되면,이 값은 설정되지 않습니다 "http : // nodejs .org/api/child_process.html # child_proces s_child_stdout. 즉, 0.10.10부터'.stdout' 속성에 액세스 할 때 코드가 실패합니다. 문제를 해결하면 답변을 +1 해 드리겠습니다. – mklement0

+0

네 말이 맞아! 이것은 빤다. process.stdout과 같은 쓰기 가능한 스트림에 'data'이벤트와 같은 것이 있다고 생각하지 않습니다. 따라서 어떤 방식 으로든 출력에 도달 할 수 있는지 여부를 알 수 없습니다 :-( – Matthias

+3

+1 (OP의 문제를 해결하지 못하더라도) "+'{stdio : 'inherit'}'기법 : 누군가 프로세스를 '서브 클래 싱 (subclassing)'함으로써 * 프로세스 자체에 대한 해결책을 찾았다. .stdout.write()'메소드를 사용하지만, 슬프게도, * 자식 프로세스가 공유 스트림에 쓰는 것이 작동하지 않습니다 : https://gist.github.com/bsatrom/1349384 – mklement0