Рассмотрим следующую программу 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. Поток stdout test.c буферизуется, и при запуске в терминале, как только будет достигнут \n, буфер очищается, но когда порождается таким образом с помощью node, буфер не очищается. Это может быть разрешено путем сброса 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 без изменения кода test.c? Или путем эмуляции терминала или нереста процесса или любого другого метода?
Ура!