逐行解析生成的 node.js 子进程的输出

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/9781214/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-02 15:22:19  来源:igfitidea点击:

Parse output of spawned node.js child process line by line

node.jsphantomjs

提问by Jesse Fulton

I have a PhantomJS/CasperJS script which I'm running from within a node.js script using process.spawn(). Since CasperJS doesn't support require()ing modules, I'm trying to print commands from CasperJS to stdoutand then read them in from my node.js script using spawn.stdout.on('data', function(data) {});in order to do things like add objects to redis/mongoose (convoluted, yes, but seems more straightforward than setting up a web service for this...) The CasperJS script executes a series of commands and creates, say, 20 screenshots which need to be added to my database.

我有一个 PhantomJS/CasperJS 脚本,我正在使用process.spawn(). 由于 CasperJS 不支持require()ing 模块,我试图从 CasperJS 打印命令stdout,然后使用我的 node.js 脚本读取它们spawn.stdout.on('data', function(data) {});,以便执行诸如将对象添加到 redis/mongoose 之类的操作(令人费解,是的,但似乎比为此设置 Web 服务更直接...) CasperJS 脚本执行一系列命令并创建,例如,需要添加到我的数据库的 20 个屏幕截图。

However, I can't figure out how to break the datavariable (a Buffer?) into lines... I've tried converting it to a string and then doing a replace, I've tried doing spawn.stdout.setEncoding('utf8');but nothing seems to work...

但是,我不知道如何将data变量(a Buffer?)分解成行......我尝试将其转换为字符串然后进行替换,我尝试过spawn.stdout.setEncoding('utf8');但似乎没有任何效果......

Here is what I have right now

这是我现在拥有的

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

https://gist.github.com/2131204

采纳答案by maerics

Try this:

尝试这个:

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

Note that the "data" event might not necessarily break evenly between lines of output, so a single line might span multiple data events.

请注意,“数据”事件可能不一定在输出行之间均匀中断,因此一行可能跨越多个数据事件。

回答by Sam Day

I've actually written a Node library for exactly this purpose, it's called stream-splitter and you can find it on Github: samcday/stream-splitter.

我实际上正是为此目的编写了一个 Node 库,它被称为 stream-splitter,你可以在 Github 上找到它:samcday/stream-splitter

The library provides a special Streamyou can pipe your casper stdout into, along with a delimiter (in your case, \n), and it will emit neat tokenevents, one for each line it has split out from the input Stream. The internal implementation for this is very simple, and delegates most of the magic to substack/node-bufferswhich means there's no unnecessary Bufferallocations/copies.

该库提供了一个特殊的,Stream您可以将您的 casper stdout 和一个分隔符(在您的情况下,\n)一起传输到其中,它将发出整齐的token事件,它从 input 中分离出的每一行都有一个事件Stream。内部实现非常简单,并将大部分魔法委托给子堆栈/节点缓冲区,这意味着没有不必要的Buffer分配/副本。

回答by nyctef

I found a nicer way to do this with just pure node, which seems to work well:

我找到了一种更好的方法来使用纯节点来做到这一点,这似乎运行良好:

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 */)

回答by mako

Adding to maerics' answer, which does not deal properly with cases where only part of a line is fed in a data dump (theirs will give you the first part and the second part of the line individually, as two separate lines.)

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

usage:

用法:

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

回答by Rick

You can give this a try. It will ignore any empty lines or empty new line breaks.

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

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

回答by Julio

Old stuff but still useful...

旧的东西,但仍然有用...

I have made a custom stream Transform subclass for this purpose.

为此,我制作了一个自定义流转换子类。

See https://stackoverflow.com/a/59400367/4861714

https://stackoverflow.com/a/59400367/4861714