Рассмотрим следующую программу на 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);
}
Что должно вывести строку на стандартный вывод, строку на стандартный вывод, затем дождаться ввода пользователя, затем еще одну строку на стандартный вывод и еще одну строку на стандартный вывод. Очень просто! При компиляции и запуске в командной строке вывод программы по завершении (пользовательский ввод получен для 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, буфер сбрасывается, но при создании таким образом с помощью узла буфер не сбрасывается. Эту проблему можно решить, либо сбрасывая стандартный вывод после каждой печати, либо изменяя поток стандартного вывода на небуферизованный, чтобы он немедленно сбрасывал все данные. Предполагая, что источник 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? Либо эмуляцией терминала, либо созданием процесса, либо любым другим методом?
Ваше здоровье!