Js 产生子进程并获得终端输出

我有一个脚本,它输出‘ hi’,休眠一秒钟,输出‘ hi’,休眠一秒钟,以此类推。现在我认为我可以用这个模型来解决这个问题。

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


temp.stdout.pipe(process.stdout);

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

186128 次浏览

我还在尝试使用 Node.js,但我有一些想法。首先,我认为您需要使用 execFile而不是 spawn; execFile用于当您有脚本的路径时,而 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. 向子进程的 stdout 溪流(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());
});

儿童:

setInterval(function() {
process.stdout.write("hi");
}, 1000); // or however else you want to run a timer

家长:

require('child_process').fork('./childfile.js');
// fork'd children use the parent's stdio

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

Spawn 返回一个 Child 对象,然后你可以用它来返回 倾听事件。事件是:

  • 课程: 儿童进程
    • 事件: ‘ error’
    • 事件: 「退出」
    • 事件: 「关闭」
    • 事件: “断开”
    • 事件: 「讯息」

还有一些 来自 child 对象的对象,它们是:

  • 课程: 儿童进程
    • 孩子
    • 孩子 Stdout
    • 孩子
    • 孩子,工作室
    • 孩子
    • 孩子,有联系
    • 杀死([信号])
    • Send (message [ ,sendHandle ][ ,callback ])
    • Disconnect ()

点击这里查看更多关于 child Object: https://nodejs.org/api/child_process.html的信息

异步的

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

Child _ process. spawn (...) ; (Node 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. stein nSync (...) ; (Node v0.11.12 +)

这种方法的问题:

  • 如果脚本需要一段时间才能完成,那么您的服务器将挂起 那么长的时间!
  • 只有在脚本执行完成之后,才会返回 stdout 已经运行完 。因为它是同步的,所以不能继续 直到当前线路完成。因此它无法捕获 “ 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”命令获取日志输出有点麻烦。在父控制台中没有显示依赖项的实时日志记录。

最简单的方法做什么原来的海报想要的似乎是这样(产生 npm 在窗口和日志一切到父控制台) :

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

它是基于承诺的,因此您可以链接多个命令。它甚至与 child_process.spawn函数签名兼容,所以在任何使用它的地方它都应该是一个替代品。

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

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

exec添加一个样本,因为我也需要现场反馈,直到脚本完成后才得到任何反馈。exec 是的返回一个 事件发射器,与许多声称只有 spawn以这种方式工作的说法相反。

这是对我对公认答案所作评论的更全面的补充。

Exec 的接口类似于 spawn:

// INCLUDES
import * as childProcess from 'child_process'; // ES6 Syntax
    

    

// DEFINES
let exec = childProcess.exec; // Use 'var' for more proper
// semantics, or 'const' it all
// if that's your thing; though 'let' is
// true-to-scope;


// Return an EventEmitter to work with, though
// you can also chain stdout too:
// (i.e. exec( ... ).stdout.on( ... ); )
let childProcess = exec
(
'./binary command -- --argument argumentValue',
( error, stdout, stderr ) =>
{    // When the process completes:
if( error )
{
console.log( `${error.name}: ${error.message}` );
console.log( `[STACK] ${error.stack}` );
}
            

console.log( stdout );
console.log( stderr );
callback();                // Gulp stuff
}
);

现在它就像为 stdout注册一个事件处理程序一样简单:

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

至于 stderr:

childProcess.stderr.on( 'data', data => console.log( `[ERROR]: ${data}` ) );

您还可以将 pipe标准输出转换为主进程的标准输出:

childProcess.stdout.pipe( process.stdout );

一点也不坏

类 PHP 的 passthru

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

当我正在生成一个 Python3脚本时,我遇到了以上所有方法都不起作用的情况。我可以从 stdout 获取数据,但只能在孩子终止后才能获取。

事实证明,Python 在默认情况下缓冲标准输出。通过将 -u作为 python3的命令行参数,可以禁用标准输出缓冲。

我感兴趣的是运行一个从我的终端获取输入和输出的脚本,一旦子脚本完成,它将关闭我的进程。

import { spawn } from 'node:child_process'
import process from 'node:process'


const script = spawn('path/to/script', { stdio: 'inherit' })
script.on('close', process.exit)