[英]Parse output of spawned node.js child process line by line
我有一个 PhantomJS/CasperJS 脚本,我正在使用process.spawn()
从 node.js 脚本中运行它。 由于 CasperJS 不支持require()
ing 模块,我试图将命令从 CasperJS 打印到stdout
,然后使用spawn.stdout.on('data', function(data) {});
从我的 node.js 脚本中读取它们spawn.stdout.on('data', function(data) {});
为了执行诸如将对象添加到 redis/mongoose 之类的事情(令人费解,是的,但似乎比为此设置 Web 服务更直接...)CasperJS 脚本执行一系列命令并创建,例如,20 个需要要添加到我的数据库中。
但是,我不知道如何将data
变量( 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);
});
尝试这个:
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 上找到它: samcday/stream-splitter 。
该库提供了一个特殊的Stream
您可以将 casper stdout 与分隔符(在您的情况下,\\n)一起通过管道Stream
到其中,它将发出整洁的token
事件,一个用于从输入Stream
分离出来的每一行。 内部实现非常简单,并将大部分魔法委托给子堆栈/节点缓冲区,这意味着没有不必要的Buffer
分配/副本。
我找到了一种更好的方法来使用纯节点来做到这一点,这似乎运行良好:
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 */)
添加到 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]);
}
});
});
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.