Parse output of spawned node.js proces potomny linia po linii

Mam skrypt PhantomJS / CasperJS, który uruchamiam z poziomu węzła.skrypt js przy użyciu process.spawn(). Ponieważ CasperJS nie obsługuje modułów require() ing, próbuję wydrukować polecenia z CasperJS do stdout, a następnie odczytać je z mojego węzła.skrypt js używający spawn.stdout.on('data', function(data) {}); w celu zrobienia takich rzeczy jak dodawanie obiektów do redis/mongoose (zawiłe, tak, ale wydaje się prostsze niż skonfigurowanie usługi internetowej do tego...) Skrypt Kacperjs wykonuje szereg poleceń i tworzy powiedzmy 20 zrzutów ekranu które należy dodać do mojej bazy danych.

Nie mogę jednak wymyślić, jak złamać zmienną data (a Buffer?) w linie... Próbowałem przekonwertować go na ciąg znaków, a następnie wykonać replace, próbowałem zrobić spawn.stdout.setEncoding('utf8');, ale nic nie działa...

Oto co mam teraz

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

Author: hippietrail, 2012-03-20

4 answers

Spróbuj tego:

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

Zauważ, że zdarzenie "data" niekoniecznie musi równomiernie rozchodzić się między wierszami wyjścia, więc pojedyncza linia może obejmować wiele zdarzeń danych.

 14
Author: maerics,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-03-20 04:20:09

Napisałem bibliotekę węzłów do tego właśnie celu, nazywa się stream-splitter i można ją znaleźć na Githubie: samcday/stream-splitter .

Biblioteka zapewnia specjalne Stream, do którego można przesyłać swoje casper stdout, wraz z ogranicznikiem (w Twoim przypadku \n), i będzie emitować zdarzenia token, po jednym dla każdej linii, która została oddzielona od wejścia Stream. Wewnętrzna implementacja tego jest bardzo prosta i przekazuje większość magii do substack / node-buffers co oznacza, że nie ma niepotrzebnych Buffer alokacji/kopii.

 12
Author: Sam Day,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-07-07 07:06:07

Dodanie do odpowiedzi maericsa, która nie radzi sobie poprawnie z przypadkami, w których tylko część linii jest podawana w zrzut danych (ich pierwsza część i druga część linii osobno, jako dwie oddzielne linie.)

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])
        }
    }
}

Użycie:

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
Author: mako,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-06-30 01:49:49

Możesz spróbować. Zignoruje wszystkie puste linie lub puste podziały nowych linii.

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]);
        }
    });
});
 0
Author: Rick,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-11-07 02:35:35