Разбирать вывод порожденного дочернего процесса node.js построчно - PullRequest
19 голосов
/ 20 марта 2012

У меня есть скрипт PhantomJS / CasperJS, который я запускаю из скрипта node.js, используя process.spawn(). Поскольку CasperJS не поддерживает require() модули ing, я пытаюсь распечатать команды из CasperJS в stdout, а затем прочитать их из моего скрипта node.js, используя spawn.stdout.on('data', function(data) {}); для таких вещей, как добавление объектов в redis / mongoose (сложный, да, но кажется более простым, чем настройка веб-службы для этого ...) Сценарий CasperJS выполняет серию команд и создает, скажем, 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

Ответы [ 5 ]

14 голосов
/ 20 марта 2012

Попробуйте это:

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

Обратите внимание, что событие «data» может не обязательно разбиваться равномерно между строками вывода, поэтому одна строка может охватывать несколько событий данных.

12 голосов
/ 07 июля 2012

Я фактически написал библиотеку Node именно для этой цели, она называется stream-splitter, и вы можете найти ее на Github: samcday / stream-splitter .

Библиотека предоставляет специальный Stream, в который вы можете направить свой стандартный вывод casper вместе с разделителем (в вашем случае \ n), и она будет выдавать аккуратные token события, по одному для каждой выделенной строки с входа Stream. Внутренняя реализация для этого очень проста и делегирует большую часть магии substack / node-buffers , что означает отсутствие ненужных Buffer выделений / копий.

2 голосов
/ 09 мая 2015

Добавление к ответу 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 ^^
}) )
1 голос
/ 12 февраля 2019

Я нашел лучший способ сделать это только с чистым узлом, который, кажется, хорошо работает:

const childProcess = require('child_process');
const readline = require('readline');

const cspr = childProcess.spawn(bin, args);

const rl = readline.createInterface({ input: cspr.stdout });
rl.on('line', line => /* handle line here */)

0 голосов
/ 07 ноября 2016

Вы можете попробовать. Он будет игнорировать любые пустые строки или пустые разрывы новой строки.

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]);
        }
    });
});
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...