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

Node.js生成子进程并实时获取终端输出,node.js,spawn,capture-output,Node.js,Spawn,Capture Output,我有一个脚本,输出“hi”,休眠一秒钟,输出“hi”,休眠一秒钟,依此类推。现在我想我可以用这个模型来解决这个问题 var spawn = require('child_process').spawn, temp = spawn('PATH TO SCRIPT WITH THE ABOVE BEHAVIOUR'); temp.stdout.pipe(process.stdout); 现在的问题是,为了显示输出,需要完成任务。据我所知,这是因为新生成的进程具有执行控制权。显然node.j

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

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

temp.stdout.pipe(process.stdout);

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

我仍然对Node.js感到困惑,但我有一些想法。首先,我认为您需要使用
execFile
而不是
spawn
execFile
用于有脚本路径时,而
spawn
用于执行Node.js可以根据系统路径解析的已知命令

1.要处理缓冲输出,请执行以下操作: 2.将侦听器添加到子进程的stdout() 此外,似乎还有一些选项可以让您从节点的控制终端分离生成的进程,这将允许它异步运行。我还没有对此进行测试,但在中有这样的例子:

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()); 
});
儿童:

家长:

require('child_process').fork('./childfile.js');
// fork'd children use the parent's stdio
现在容易多了(6年后)

Spawn返回一个childObject,然后您可以使用它侦听事件。活动包括:

  • 类别:ChildProcess
    • 事件:“错误”
    • 事件:“退出”
    • 事件:“关闭”
    • 事件:“断开连接”
    • 事件:“消息”
childObject中还有一组对象,它们是:

  • 类别:ChildProcess
    • child.stdin
    • 童装
    • child.stderr
    • 童装
    • child.pid
    • 儿童网络
    • child.kill([信号])
    • 发送(消息[,发送句柄][,回调])
    • child.disconnect()
请参阅此处有关childObject的更多信息:

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

(节点v0.1.90)

下面是如何使用回调+异步方法的

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);
    });
}
使用上述方法,您可以将脚本的每一行输出发送到客户端(例如,当您在
stdout
stderr
上接收事件时,使用Socket.io发送每一行)

同步的 如果希望节点停止正在执行的操作并等待脚本完成,则可以使用同步版本:

(节点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);

当我在子进程中生成npm时,从“npm install”命令获取日志输出时遇到了一些问题。依赖项的实时日志记录未显示在父控制台中

完成原始海报所需的最简单的方法似乎是这样(在windows上生成npm并将所有内容记录到父控制台):


我发现自己经常需要这个功能,所以我将它打包到一个名为的库中。它应该允许您执行命令并实时查看输出。要简单安装,请执行以下操作:

npm install std-pour
然后执行命令并实时查看输出就足够简单了:

const { pour } = require('std-pour');
pour('ping', ['8.8.8.8', '-c', '4']).then(code => console.log(`Error Code: ${code}`));

它基于承诺,因此您可以链接多个命令。它甚至与函数签名兼容,因此无论您在哪里使用它,它都应该是一个方便的替代品。

以下是我发现的最干净的方法:

require("child_process").spawn('bash', ['./script.sh'], {
  cwd: process.cwd(),
  detached: true,
  stdio: "inherit"
});

exec
添加一个示例,因为我也需要实时反馈,直到脚本完成后才得到任何反馈
exec
确实返回一个EventEmitter,这与许多声称只有
spawn
才能以这种方式工作的说法相反

这更彻底地补充了我对公认答案的评论

exec的接口类似于spawn:

//包括
从“子进程”导入*作为子进程;//ES6语法
//定义
让exec=childProcess.exec;//使用“var”更恰当地表示
//语义,或“const”全部
//如果那是你的事;虽然“让”是
//忠实于范围;
//不过,返回一个EventEmitter来使用
//您也可以链接stdout:
//(即exec(…).stdout.on(…);)
让childProcess=exec
(
'./二进制命令--argument argumentValue',
(错误,标准输出,标准输出)=>
{//当流程完成时:
如果(错误)
{   
log(`${error.name}:${error.message}`);
log(`[STACK]${error.STACK}`);
}
控制台日志(stdout);
控制台日志(stderr);
callback();//吞咽东西
}
);
现在只需为
stdout
注册一个事件处理程序即可:

childProcess.stdout.on('data',data=>console.log(data));
对于
stderr

childProcess.stderr.on('data',data=>console.log(`[ERROR]:${data}`));
您还可以
管道
标准输出到主进程的标准输出:

childProcess.stdou
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);
var args = ['install'];

var options = {
    stdio: 'inherit' //feed all child process logging into parent process
};

var childProcess = spawn('npm.cmd', args, options);
childProcess.on('close', function(code) {
    process.stdout.write('"npm install" finished with code ' + code + '\n');
});
npm install std-pour
const { pour } = require('std-pour');
pour('ping', ['8.8.8.8', '-c', '4']).then(code => console.log(`Error Code: ${code}`));
require("child_process").spawn('bash', ['./script.sh'], {
  cwd: process.cwd(),
  detached: true,
  stdio: "inherit"
});
import { spawn } from 'child_process';

export default async function passthru(exe, args, options) {
    return new Promise((resolve, reject) => {
        const env = Object.create(process.env);
        const child = spawn(exe, args, {
            ...options,
            env: {
                ...env,
                ...options.env,
            },
        });
        child.stdout.setEncoding('utf8');
        child.stderr.setEncoding('utf8');
        child.stdout.on('data', data => console.log(data));
        child.stderr.on('data', data => console.log(data));
        child.on('error', error => reject(error));
        child.on('close', exitCode => {
            console.log('Exit code:', exitCode);
            resolve(exitCode);
        });
    });
}
const exitCode = await passthru('ls', ['-al'], { cwd: '/var/www/html' })