Node.js 生成子进程并实时获取终端输出

新手上路,请多包涵

我有一个脚本输出’hi’,休眠一秒钟,输出’hi’,休眠1秒,依此类推。现在我想我可以用这个模型解决这个问题。

 var spawn = require('child_process').spawn,
temp    = spawn('PATH TO SCRIPT WITH THE ABOVE BEHAVIOUR');

temp.stdout.pipe(process.stdout);

现在的问题是需要完成任务才能显示输出。据我了解,这是因为新生成的进程具有执行控制权。显然 node.js 不支持线程所以有什么解决方案吗?我的想法是可能运行两个实例,第一个用于创建任务的特定目的,并让它将输出通过管道传输到第二个实例的进程,考虑到这可以实现。

原文由 foklepoint 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 2.7k
2 个回答

我仍然对 Node.js 感到困惑,但我有一些想法。首先,我相信您需要使用 execFile 而不是 spawnexecFile 用于当您拥有脚本的路径时,而 spawn 用于执行 Node.js 可以针对您的系统路径解析的众所周知的命令。

1. 提供一个回调 来处理缓冲的输出:

 var child = require('child_process').execFile('path/to/script', [
    'arg1', 'arg2', 'arg3',
], function(err, stdout, stderr) {
    // Node.js will invoke this callback when process terminates.
    console.log(stdout);
});

2. 为子进程的标准输出 添加一个监听器( 9thport.net

 var child = require('child_process').execFile('path/to/script', [
    'arg1', 'arg2', 'arg3' ]);
// use event hooks to provide a callback to execute when data are available:
child.stdout.on('data', function(data) {
    console.log(data.toString());
});

此外,似乎有一些选项可以让您将生成的进程从 Node 的控制终端中分离出来,这将允许它异步运行。我还没有对此进行测试,但是 API 文档 中的示例如下所示:

 child = require('child_process').execFile('path/to/script', [
    'arg1', 'arg2', 'arg3',
], {
    // detachment and ignored stdin are the key here:
    detached: true,
    stdio: [ 'ignore', 1, 2 ]
});
// and unref() somehow disentangles the child's event loop from the parent's:
child.unref();
child.stdout.on('data', function(data) {
    console.log(data.toString());
});

原文由 RubyTuesdayDONO 发布,翻译遵循 CC BY-SA 4.0 许可协议

现在(6 年后)容易多了!

Spawn 返回一个 childObject ,然后您可以使用它来 监听事件。这些事件是:

  • 类:子进程
    • 事件:“错误”
    • 事件:’退出’
    • 事件:’关闭’
    • 事件:’断开连接’
    • 事件:’消息’

还有一堆 来自 childObject 的对象,它们是:

  • 类:子进程
    • child.stdin
    • 孩子.stdout
    • 孩子.stderr
    • child.stdio
    • 孩子.pid
    • 儿童.connected
    • child.kill([信号])
    • child.send(消息[, sendHandle][, 回调])
    • child.disconnect()

在此处查看有关 childObject 的更多信息: https ://nodejs.org/api/child_process.html

异步

如果你想在后台运行你的进程,而节点仍然能够继续执行,请使用异步方法。您仍然可以选择在流程完成后以及流程有任何输出时执行操作(例如,如果您想将脚本的输出发送到客户端)。

child_process.spawn(…); (节点 v0.1.90)

 var spawn = require('child_process').spawn;
var child = spawn('node ./commands/server.js');

// You can also use a variable to save the output
// for when the script closes later
var scriptOutput = "";

child.stdout.setEncoding('utf8');
child.stdout.on('data', function(data) {
    //Here is where the output goes

    console.log('stdout: ' + data);

    data=data.toString();
    scriptOutput+=data;
});

child.stderr.setEncoding('utf8');
child.stderr.on('data', function(data) {
    //Here is where the error output goes

    console.log('stderr: ' + data);

    data=data.toString();
    scriptOutput+=data;
});

child.on('close', function(code) {
    //Here you can get the exit code of the script

    console.log('closing code: ' + code);

    console.log('Full output of script: ',scriptOutput);
});

以下是 您将如何使用回调 + 异步方法

 var child_process = require('child_process');

console.log("Node Version: ", process.version);

run_script("ls", ["-l", "/home"], function(output, exit_code) {
    console.log("Process Finished.");
    console.log('closing code: ' + exit_code);
    console.log('Full output of script: ',output);
});

console.log ("Continuing to do node things while the process runs at the same time...");

// This function will output the lines from the script
// AS is runs, AND will return the full combined output
// as well as exit code when it's done (using the callback).
function run_script(command, args, callback) {
    console.log("Starting Process.");
    var child = child_process.spawn(command, args);

    var scriptOutput = "";

    child.stdout.setEncoding('utf8');
    child.stdout.on('data', function(data) {
        console.log('stdout: ' + data);

        data=data.toString();
        scriptOutput+=data;
    });

    child.stderr.setEncoding('utf8');
    child.stderr.on('data', function(data) {
        console.log('stderr: ' + data);

        data=data.toString();
        scriptOutput+=data;
    });

    child.on('close', function(code) {
        callback(scriptOutput,code);
    });
}

使用上述方法,您可以将脚本的每一行输出发送到客户端(例如,当您在 stdoutstderr 上接收事件时,使用 Socket.io 发送每一行) .

同步

如果你想让节点停止它正在做的事情并 等到脚本完成,你可以使用同步版本:

child_process.spawnSync(…); (节点 v0.11.12+)

这种方法的问题:

  • 如果脚本需要一段时间才能完成,您的服务器将挂起这段时间!
  • 只有在脚本运行完毕后才会返回标准输出。因为它是同步的,所以在当前行完成之前它无法继续。因此,在生成行完成之前,它无法捕获“stdout”事件。

如何使用它:

 var child_process = require('child_process');

var child = child_process.spawnSync("ls", ["-l", "/home"], { encoding : 'utf8' });
console.log("Process finished.");
if(child.error) {
    console.log("ERROR: ",child.error);
}
console.log("stdout: ",child.stdout);
console.log("stderr: ",child.stderr);
console.log("exist code: ",child.status);

原文由 Katie 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题