Search code examples
javascriptnode.jsperlstdoutspawn

Node.js child.spawn stdout "live" at every line


i am tying to use the output of a Perl script in Node.js

for (my $i=10;$i<100 ;$i+=30 )
{
    printf "$i\n";
    sleep(1);
}

This script is called by the child_process.spawn method. My problem is, that i need to work with every single output. Is there a way to start a event as soon as perl send a new line to stdout? In my actual code i can see the output as a bulk after the perl script finished running and it is not possible to work with single lines

function setStuff() {
    var command = "perl";
    var scriptpath = "script.pl";
    var arg = [scriptpath];
    run(command, arg);
}
function run(cmd, arg) {
 var spawn = require('child_process').spawn;
    var command = spawn(cmd, arg, {detached: true, stdout: 'pipe'});

    command.unref();
    var lineBuffer = "";
    command.stdout.pipe(process.stdout);
    command.stdout.on('data', function (data) {
        lineBuffer += data.toString();
        var lines = lineBuffer.split("\n");
        for (var i = 0; i < lines.length - 1; i++) {
            var line = lines[i];
            console.log(line);
        }
    });
}

Solution

  • Put this on your perl file to disable buffering on output :

    select(STDOUT); $| =1;
    

    You also need to fix your on 'data' handler so that you are not managing the lineBuffer var as you consume the data. To fix it :

    command.stdout.on('data', function (data) {
        var lines = (lineBuffer + data).split("\n");
        if(data[data.length-1] != '\n') {
            lineBuffer = lines.pop();
        }else{
            lineBuffer = '';
        }
        for (var i = 0; i < lines.length - 1; i++) {
            var line = lines[i];
            console.log(line);
        }
    });
    

    Also, is there a missing stdout.setEncoding('utf8'); ?