Вывод синтаксиса порожденного дочернего процесса node.js по строкам
У меня есть PhantomJS/CasperJS script, который я запускаю из node.js script с помощью process.spawn()
. Поскольку CasperJS не поддерживает модули require()
ing, я пытаюсь распечатать команды от CasperJS до stdout
, а затем прочитать их с помощью node.js script с помощью spawn.stdout.on('data', function(data) {});
, чтобы сделать что-то вроде добавлять объекты в redis/mongoose (свернуто, да, но кажется более простым, чем настройка веб-службы для этого...) CasperJS script выполняет серию команд и создает, скажем, 20 скриншотов, которые необходимо добавить в моя база данных.
Однако я не могу понять, как разбить переменную data
(a Buffer
?) на строки... Я попытался преобразовать ее в строку, а затем выполнить замену, я пробовал делая spawn.stdout.setEncoding('utf8');
, но ничего не работает...
Вот что я имею прямо сейчас
var spawn = require('child_process').spawn;
var bin = "casperjs"
//googlelinks.js is the example given at http://casperjs.org/#quickstart
var args = ['scripts/googlelinks.js'];
var cspr = spawn(bin, args);
//cspr.stdout.setEncoding('utf8');
cspr.stdout.on('data', function (data) {
var buff = new Buffer(data);
console.log("foo: " + buff.toString('utf8'));
});
cspr.stderr.on('data', function (data) {
data += '';
console.log(data.replace("\n", "\nstderr: "));
});
cspr.on('exit', function (code) {
console.log('child process exited with code ' + code);
process.exit(code);
});
https://gist.github.com/2131204
Ответы
Ответ 1
Попробуйте следующее:
cspr.stdout.setEncoding('utf8');
cspr.stdout.on('data', function(data) {
var str = data.toString(), lines = str.split(/(\r?\n)/g);
for (var i=0; i<lines.length; i++) {
// Process the line, noting it might be incomplete.
}
});
Обратите внимание, что событие "данные" может не обязательно равномерно разбиваться на строки вывода, поэтому одна строка может охватывать несколько событий данных.
Ответ 2
Я на самом деле написал библиотеку Node для этой цели, она называется stream-splitter, и вы можете найти ее на Github: samcday/stream-splitter.
В библиотеке есть специальный Stream
, который вы можете подключить к вашему казну stdout вместе с разделителем (в вашем случае \n), и он будет выделять аккуратные события token
, по одному для каждой строки, которую он разделил от входа Stream
. Внутренняя реализация для этого очень проста и делегирует большую часть магии substack/node-buffers, что означает отсутствие ненужных Buffer
распределений/копий.
Ответ 3
Добавление ответа maerics, который не имеет отношения к случаям, когда только одна часть строки подается в дамп данных (их команда будет давать вам первую часть и вторую часть строки отдельно, как две отдельные строки. )
var _breakOffFirstLine = /\r?\n/
function filterStdoutDataDumpsToTextLines(callback){ //returns a function that takes chunks of stdin data, aggregates it, and passes lines one by one through to callback, all as soon as it gets them.
var acc = ''
return function(data){
var splitted = data.toString().split(_breakOffFirstLine)
var inTactLines = splitted.slice(0, splitted.length-1)
var inTactLines[0] = acc+inTactLines[0] //if there was a partial, unended line in the previous dump, it is completed by the first section.
acc = splitted[splitted.length-1] //if there is a partial, unended line in this dump, store it to be completed by the next (we assume there will be a terminating newline at some point. This is, generally, a safe assumption.)
for(var i=0; i<inTactLines.length; ++i){
callback(inTactLines[i])
}
}
}
использование:
process.stdout.on('data', filterStdoutDataDumpsToTextLines(function(line){
//each time this inner function is called, you will be getting a single, complete line of the stdout ^^
}) )
Ответ 4
Вы можете попробовать. Он будет игнорировать любые пустые строки или пустые новые разрывы строк.
cspr.stdout.on('data', (data) => {
data = data.toString().split(/(\r?\n)/g);
data.forEach((item, index) => {
if (data[index] !== '\n' && data[index] !== '') {
console.log(data[index]);
}
});
});