生成的node.jssubprocess的输出逐行parsing

我有一个使用process.spawn()从node.js脚本运行的PhantomJS / CasperJS脚本。 由于CasperJS不支持require() ing模块,我试图从CasperJS打印命令到stdout ,然后从我的node.js脚本中使用spawn.stdout.on('data', function(data) {}); 为了做一些事情,比如将对象添加到redis / mongoose(复杂的,是的,但似乎比为此设置一个Web服务更简单)。CasperJS脚本执行一系列命令并创build20个截图,这些截图需要被添加到我的数据库。

然而,我想不出如何将datavariables(一个Buffer ?)分解成行…我试过把它转换成一个string,然后做一个replace,我试过做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

尝试这个:

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

请注意,“数据”事件可能不一定会在输出行之间平均分配,因此单个行可能会跨越多个数据事件。

实际上,我已经写了一个Node库来达到这个目的,它被称为stream-splitter,你可以在Github上find它: samcday / stream-splitter 。

该库提供了一个特殊的Stream你可以将你的casper标准输出到一个分隔符(在你的情况下,\ n),它会发出整齐的token事件,从inputStream分离出来的每一行。 内部的实现非常简单,并将大部分的魔力委托给了substack / node-buffers ,这意味着没有不必要的Buffer分配/副本。

添加到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 ^^ }) ) 

你可以试试这个。 它将忽略任何空行或空的新换行符。

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