如何玩转父子进程如何传递参数child

利用NodeJS的子进程(child_process)调用系统命令的方法分享
字体:[ ] 类型:转载 时间:
child_process即子进程可以创建一个系统子进程并执行shell命令,在与系统层面的交互上挺有用处
NodeJS子进程简介 NodeJS子进程提供了与系统交互的重要接口,其主要API有: 标准输入、标准输出及标准错误输出的接口。 NodeJS子进程简介 NodeJS 子进程提供了与系统交互的重要接口,其主要 API 有: 标准输入、标准输出及标准错误输出的接口 child.stdin 获取标准输入 child.stdout 获取标准输出 child.stderr 获取标准错误输出 获取子进程的PID:child.pid 提供生成子进程的重要方法:child_process.spawn(cmd, args=[], [options]) 提供直接执行系统命令的重要方法:child_process.exec(cmd, [options], callback) 提供杀死进程的方法:child.kill(signal='SIGTERM') 实例一:利用子进程获取系统内存使用情况 将以下代码保存为 free.js:
代码如下: var spawn = require('child_process').spawn, free = spawn('free', ['-m']); // 捕获标准输出并将其打印到控制台 free.stdout.on('data', function (data) { console.log('标准输出:\n' + data); }); // 捕获标准错误输出并将其打印到控制台 free.stderr.on('data', function (data) { console.log('标准错误输出:\n' + data); }); // 注册子进程关闭事件 free.on('exit', function (code, signal) { console.log('子进程已退出,代码:' + code); });
执行代码后的结果: $ node free.js 标准输出: total used free shared buffers cached Mem: 74 0 135 959 -/+ buffers/cache: 879 3070 Swap: 5 子进程已退出,代码:0 以上输出相当与在命令行执行:free -m 命令。 通过这个简单的例子我们已经对子进程的使用有所了解,下面再来一个示例,用于演示exec 的使用方法。 实例二:利用子进程统计系统登录次数 将下面代码保存为 last.js
代码如下: var exec = require('child_process').exec, last = exec('last | wc -l'); last.stdout.on('data', function (data) { console.log('标准输出:' + data); }); last.on('exit', function (code) { console.log('子进程已关闭,代码:' + code); });
执行代码: $ node last.js 标准输出:203 子进程已关闭,代码:0 其与直接在命令行输入:last | wc -l 的结果是一样的。
您可能感兴趣的文章:
大家感兴趣的内容
12345678910
最近更新的内容
常用在线小工具Nodejs进阶:如何玩转子进程(child_process)
本文摘录自个人总结《Nodejs学习笔记》,更多章节及更新,请访问 。欢迎加群交流,群号 。
在node中,child_process这个模块非常重要。掌握了它,等于在node的世界开启了一扇新的大门。熟悉shell脚本的同学,可以用它来完成很多有意思的事情,比如文件压缩、增量部署等,感兴趣的同学,看文本文后可以尝试下。
举个简单的例子:
const spawn = require('child_process').
const ls = spawn('ls', ['-lh', '/usr']);
ls.stdout.on('data', (data) =& {
console.log(`stdout: ${data}`);
ls.stderr.on('data', (data) =& {
console.log(`stderr: ${data}`);
ls.on('close', (code) =& {
console.log(`child process exited with code ${code}`);
几种创建子进程的方式
注意事项:
下面列出来的都是异步创建子进程的方式,每一种方式都有对应的同步版本。
.exec()、.execFile()、.fork()底层都是通过.spawn()实现的。
.exec()、execFile()额外提供了回调,当子进程停止的时候执行。
child_process.spawn(command[, args][, options])
child_process.exec(command[, options][, callback])
child_process.execFile(file[, args][, options][, callback])
child_process.fork(modulePath[, args][, options])
child_process.exec(command[, options][, callback])
创建一个shell,然后在shell里执行命令。执行完成后,将stdout、stderr作为参数传入回调方法。
spawns a shell and runs a command within that shell, passing the stdout and stderr to a callback function when complete.
例子如下:
执行成功,error为null;执行失败,error为Error实例。error.code为错误码,
stdout、stderr为标准输出、标准错误。默认是字符串,除非options.encoding为buffer
var exec = require('child_process').
// 成功的例子
exec('ls -al', function(error, stdout, stderr){
if(error) {
console.error('error: ' + error);
console.log('stdout: ' + stdout);
console.log('stderr: ' + typeof stderr);
// 失败的例子
exec('ls hello.txt', function(error, stdout, stderr){
if(error) {
console.error('error: ' + error);
console.log('stdout: ' + stdout);
console.log('stderr: ' + stderr);
参数说明:
cwd:当前工作路径。
env:环境变量。
encoding:编码,默认是utf8。
shell:用来执行命令的shell,unix上默认是/bin/sh,windows上默认是cmd.exe。
timeout:默认是0。
killSignal:默认是SIGTERM。
uid:执行进程的uid。
gid:执行进程的gid。
maxBuffer: 标准输出、错误输出最大允许的数据量(单位为字节),如果超出的话,子进程就会被杀死。默认是200*1024(就是200k啦)
如果timeout大于0,那么,当子进程运行超过timeout毫秒,那么,就会给进程发送killSignal指定的信号(比如SIGTERM)。
如果运行没有出错,那么error为null。如果运行出错,那么,error.code就是退出代码(exist code),error.signal会被设置成终止进程的信号。(比如CTRL+C时发送的SIGINT)
传入的命令,如果是用户输入的,有可能产生类似sql注入的风险,比如
exec('ls hello. rm -rf *', function(error, stdout, stderr){
if(error) {
console.error('error: ' + error);
console.log('stdout: ' + stdout);
console.log('stderr: ' + stderr);
Note: Unlike the exec(3) POSIX system call, child_process.exec() does not replace the existing process and uses a shell to execute the command.
child_process.execFile(file[, args][, options][, callback])
跟.exec()类似,不同点在于,没有创建一个新的shell。至少有两点影响
比child_process.exec()效率高一些。(实际待测试)
一些操作,比如I/O重定向,文件glob等不支持。
similar to child_process.exec() except that it spawns the command directly without first spawning a shell.
file: 可执行文件的名字,或者路径。
var child_process = require('child_process');
child_process.execFile('node', ['--version'], function(error, stdout, stderr){
if(error){
console.log(stdout);
child_process.execFile('/Users/a/.nvm/versions/node/v6.1.0/bin/node', ['--version'], function(error, stdout, stderr){
if(error){
console.log(stdout);
====== 扩展阅读 =======
从node源码来看,exec()、execFile()最大的差别,就在于是否创建了shell。(execFile()内部,options.shell === false),那么,可以手动设置shell。以下代码差不多是等价的。win下的shell设置有所不同,感兴趣的同学可以自己试验下。
备注:execFile()内部最终还是通过spawn()实现的, 如果没有设置 {shell: '/bin/bash'},那么 spawm() 内部对命令的解析会有所不同,execFile('ls -al .') 会直接报错。
var child_process = require('child_process');
var execFile = child_process.execF
var exec = child_process.
exec('ls -al .', function(error, stdout, stderr){
if(error){
console.log(stdout);
execFile('ls -al .', {shell: '/bin/bash'}, function(error, stdout, stderr){
if(error){
console.log(stdout);
child_process.fork(modulePath[, args][, options])
modulePath:子进程运行的模块。
参数说明:(重复的参数说明就不在这里列举)
execPath: 用来创建子进程的可执行文件,默认是/usr/local/bin/node。也就是说,你可通过execPath来指定具体的node可执行文件路径。(比如多个node版本)
execArgv: 传给可执行文件的字符串参数列表。默认是process.execArgv,跟父进程保持一致。
silent: 默认是false,即子进程的stdio从父进程继承。如果是true,则直接pipe向子进程的child.stdin、child.stdout等。
stdio: 如果声明了stdio,则会覆盖silent选项的设置。
例子1:silent
var child_process = require('child_process');
// 例子一:会打印出 output from the child
// 默认情况,silent 为 false,子进程的 stdout 等
// 从父进程继承
child_process.fork('./child.js', {
silent: false
// 例子二:不会打印出 output from the silent child
// silent 为 true,子进程的 stdout 等
// pipe 向父进程
child_process.fork('./silentChild.js', {
silent: true
// 例子三:打印出 output from another silent child
var child = child_process.fork('./anotherSilentChild.js', {
silent: true
child.stdout.setEncoding('utf8');
child.stdout.on('data', function(data){
console.log(data);
console.log('output from the child');
silentChild.js
console.log('output from the silent child');
anotherSilentChild.js
console.log('output from another silent child');
例子二:ipc
var child_process = require('child_process');
var child = child_process.fork('./child.js');
child.on('message', function(m){
console.log('message from child: ' + JSON.stringify(m));
child.send({from: 'parent'});
process.on('message', function(m){
console.log('message from parent: ' + JSON.stringify(m));
process.send({from: 'child'});
ipc git:(master)
node parent.js
message from child: {"from":"child"}
message from parent: {"from":"parent"}
例子三:execArgv
首先,process.execArgv的定义,参考。设置execArgv的目的一般在于,让子进程跟父进程保持相同的执行环境。
比如,父进程指定了--harmony,如果子进程没有指定,那么就要跪了。
var child_process = require('child_process');
console.log('parent execArgv: ' + process.execArgv);
child_process.fork('./child.js', {
execArgv: process.execArgv
console.log('child execArgv: ' + process.execArgv);
execArgv git:(master)
node --harmony parent.js
parent execArgv: --harmony
child execArgv: --harmony
例子3:execPath(TODO 待举例子)
child_process.spawn(command[, args][, options])
command:要执行的命令
options参数说明:
argv0:[String] 这货比较诡异,在uninx、windows上表现不一样。有需要再深究。
stdio:[Array] | [String] 子进程的stdio。参考
detached:[Boolean] 让子进程独立于父进程之外运行。同样在不同平台上表现有差异,具体参考
shell:[Boolean] | [String] 如果是true,在shell里运行程序。默认是false。(很有用,比如 可以通过 /bin/sh -c xxx 来实现 .exec() 这样的效果)
例子1:基础例子
var spawn = require('child_process').
var ls = spawn('ls', ['-al']);
ls.stdout.on('data', function(data){
console.log('data from child: ' + data);
ls.stderr.on('data', function(data){
console.log('error from child: ' + data);
ls.on('close', function(code){
console.log('child exists with code: ' + code);
例子2:声明stdio
var spawn = require('child_process').
var ls = spawn('ls', ['-al'], {
stdio: 'inherit'
ls.on('close', function(code){
console.log('child exists with code: ' + code);
例子3:声明使用shell
var spawn = require('child_process').
// 运行 echo "hello nodejs" | wc
var ls = spawn('bash', ['-c', 'echo "hello nodejs" | wc'], {
stdio: 'inherit',
shell: true
ls.on('close', function(code){
console.log('child exists with code: ' + code);
例子4:错误处理,包含两种场景,这两种场景有不同的处理方式。
场景1:命令本身不存在,创建子进程报错。
场景2:命令存在,但运行过程报错。
var spawn = require('child_process').
var child = spawn('bad_command');
child.on('error', (err) =& {
console.log('Failed to start child process 1.');
var child2 = spawn('ls', ['nonexistFile']);
child2.stderr.on('data', function(data){
console.log('Error msg from process 2: ' + data);
child2.on('error', (err) =& {
console.log('Failed to start child process 2.');
运行结果如下。
spawn git:(master)
node error/error.js
Failed to start child process 1.
Error msg from process 2: ls: nonexistFile: No such file or directory
例子5:echo "hello nodejs" | grep "nodejs"
// echo "hello nodejs" | grep "nodejs"
var child_process = require('child_process');
var echo = child_process.spawn('echo', ['hello nodejs']);
var grep = child_process.spawn('grep', ['nodejs']);
grep.stdout.setEncoding('utf8');
echo.stdout.on('data', function(data){
grep.stdin.write(data);
echo.on('close', function(code){
if(code!==0){
console.log('echo exists with code: ' + code);
grep.stdin.end();
grep.stdout.on('data', function(data){
console.log('grep: ' + data);
grep.on('close', function(code){
if(code!==0){
console.log('grep exists with code: ' + code);
运行结果:
spawn git:(master)
node pipe/pipe.js
grep: hello nodejs
关于options.stdio
默认值:['pipe', 'pipe', 'pipe'],这意味着:
child.stdin、child.stdout 不是undefined
可以通过监听 data 事件,来获取数据。
var spawn = require('child_process').
var ls = spawn('ls', ['-al']);
ls.stdout.on('data', function(data){
console.log('data from child: ' + data);
ls.on('close', function(code){
console.log('child exists with code: ' + code);
通过child.stdin.write()写入
var spawn = require('child_process').
var grep = spawn('grep', ['nodejs']);
setTimeout(function(){
grep.stdin.write('hello nodejs \n hello javascript');
grep.stdin.end();
grep.stdout.on('data', function(data){
console.log('data from grep: ' + data);
grep.on('close', function(code){
console.log('grep exists with code: ' + code);
异步 vs 同步
大部分时候,子进程的创建是异步的。也就是说,它不会阻塞当前的事件循环,这对于性能的提升很有帮助。
当然,有的时候,同步的方式会更方便(阻塞事件循环),比如通过子进程的方式来执行shell脚本时。
node同样提供同步的版本,比如:
spawnSync()
execSync()
execFileSync()
关于options.detached
由于木有在windows上做测试,于是先贴原文
On Windows, setting options.detached to true makes it possible for the child process to continue running after the parent exits. The child will have its own console window. Once enabled for a child process, it cannot be disabled.
在非window是平台上的表现
On non-Windows platforms, if options.detached is set to true, the child process will be made the leader of a new process group and session. Note that child processes may continue running after the parent exits regardless of whether they are detached or not. See setsid(2) for more information.
默认情况:父进程等待子进程结束。
子进程。可以看到,有个定时器一直在跑
var times = 0;
setInterval(function(){
console.log(++times);
运行下面代码,会发现父进程一直hold着不退出。
var child_process = require('child_process');
child_process.spawn('node', ['child.js'], {
// stdio: 'inherit'
通过child.unref()让父进程退出
调用child.unref(),将子进程从父进程的事件循环中剔除。于是父进程可以愉快的退出。这里有几个要点
调用child.unref()
设置detached为true
设置stdio为ignore(这点容易忘)
var child_process = require('child_process');
var child = child_process.spawn('node', ['child.js'], {
detached: true,
stdio: 'ignore'
// 备注:如果不置为 ignore,那么 父进程还是不会退出
// stdio: 'inherit'
child.unref();
将stdio重定向到文件
除了直接将stdio设置为ignore,还可以将它重定向到本地的文件。
var child_process = require('child_process');
var fs = require('fs');
var out = fs.openSync('./out.log', 'a');
var err = fs.openSync('./err.log', 'a');
var child = child_process.spawn('node', ['child.js'], {
detached: true,
stdio: ['ignore', out, err]
child.unref();
exec()与execFile()之间的区别
首先,exec() 内部调用 execFile() 来实现,而 execFile() 内部调用 spawn() 来实现。
exec() -& execFile() -& spawn()
其次,execFile() 内部默认将 options.shell 设置为false,exec() 默认不是false。
Class: ChildProcess
通过child_process.spawn()等创建,一般不直接用构造函数创建。
继承了EventEmitters,所以有.on()等方法。
当stdio流关闭时触发。这个事件跟exit不同,因为多个进程可以共享同个stdio流。参数:code(退出码,如果子进程是自己退出的话),signal(结束子进程的信号)
问题:code一定是有的吗?(从对code的注解来看好像不是)比如用kill杀死子进程,那么,code是?
参数:code、signal,如果子进程是自己退出的,那么code就是退出码,否则为null;如果子进程是通过信号结束的,那么,signal就是结束进程的信号,否则为null。这两者中,一者肯定不为null。
注意事项:exit事件触发时,子进程的stdio stream可能还打开着。(场景?)此外,nodejs监听了SIGINT和SIGTERM信号,也就是说,nodejs收到这两个信号时,不会立刻退出,而是先做一些清理的工作,然后重新抛出这两个信号。(目测此时js可以做清理工作了,比如关闭数据库等。)
SIGINT:interrupt,程序终止信号,通常在用户按下CTRL+C时发出,用来通知前台进程终止进程。
SIGTERM:terminate,程序结束信号,该信号可以被阻塞和处理,通常用来要求程序自己正常退出。shell命令kill缺省产生这个信号。如果信号终止不了,我们才会尝试SIGKILL(强制终止)。
Also, note that Node.js establishes signal handlers for SIGINT and SIGTERM and Node.js processes will not terminate immediately due to receipt of those signals. Rather, Node.js will perform a sequence of cleanup actions and then will re-raise the handled signal.
当发生下列事情时,error就会被触发。当error触发时,exit可能触发,也可能不触发。(内心是崩溃的)
无法创建子进程。
进程无法kill。(TODO 举例子)
向子进程发送消息失败。(TODO
当采用process.send()来发送消息时触发。
参数:message,为json对象,或者primitive value;sendHandle,net.Socket对象,或者net.Server对象(熟悉cluster的同学应该对这个不陌生)
.connected:当调用.disconnected()时,设为false。代表是否能够从子进程接收消息,或者对子进程发送消息。
.disconnect():关闭父进程、子进程之间的IPC通道。当这个方法被调用时,disconnect事件就会触发。如果子进程是node实例(通过child_process.fork()创建),那么在子进程内部也可以主动调用process.disconnect()来终止IPC通道。参考。
非重要的备忘点
windows平台上的cmd、bat
The importance of the distinction between child_process.exec() and child_process.execFile() can vary based on platform. On Unix-type operating systems (Unix, Linux, OSX) child_process.execFile() can be more efficient because it does not spawn a shell. On Windows, however, .bat and .cmd files are not executable on their own without a terminal, and therefore cannot be launched using child_process.execFile(). When running on Windows, .bat and .cmd files can be invoked using child_process.spawn() with the shell option set, with child_process.exec(), or by spawning cmd.exe and passing the .bat or .cmd file as an argument (which is what the shell option and child_process.exec() do).
// On Windows Only ...
const spawn = require('child_process').
const bat = spawn('cmd.exe', ['/c', 'my.bat']);
bat.stdout.on('data', (data) =& {
console.log(data);
bat.stderr.on('data', (data) =& {
console.log(data);
bat.on('exit', (code) =& {
console.log(`Child exited with code ${code}`);
const exec = require('child_process').
exec('my.bat', (err, stdout, stderr) =& {
if (err) {
console.error(err);
console.log(stdout);
Note: Certain platforms (OS X, Linux) will use the value of argv[0] for the process title while others (Windows, SunOS) will use command.
Note: Node.js currently overwrites argv[0] with process.execPath on startup, so process.argv[0] in a Node.js child process will not match the argv0 parameter passed to spawn from the parent, retrieve it with the process.argv0 property instead.
代码运行次序的问题
const cp = require('child_process');
const n = cp.fork(`${__dirname}/sub.js`);
console.log('1');
n.on('message', (m) =& {
console.log('PARENT got message:', m);
console.log('2');
n.send({ hello: 'world' });
console.log('3');
console.log('4');
process.on('message', (m) =& {
console.log('CHILD got message:', m);
process.send({ foo: 'bar' });
console.log('5');
运行node p.js,打印出来的内容如下
ch node p.js
PARENT got message: { foo: 'bar' }
CHILD got message: { hello: 'world' }
再来个例子
var fork = require('child_process').
console.log('p: 1');
fork('./c2.js');
console.log('p: 2');
// 从测试结果来看,同样是70ms,有的时候,定时器回调比子进程先执行,有的时候比子进程慢执行。
const t = 70;
setTimeout(function(){
console.log('p: 3 in %s', t);
console.log('c: 1');
关于NODE_CHANNEL_FD
child_process.fork()时,如果指定了execPath,那么父、子进程间通过NODE_CHANNEL_FD 进行通信。
Node.js processes launched with a custom execPath will communicate with the parent process using the file descriptor (fd) identified using the environment variable NODE_CHANNEL_FD on the child process. The input and output on this fd is expected to be line delimited JSON objects.
内容较多,如有错漏及建议请指出。
官方文档:
程序猿小卡NodeJS如何创建子进程 - 易百教程
位置: >> >> NodeJS如何创建子进程
如何创建子进程
以下是一个创建NodeJS子进程的例子。
var child = child_process.spawn('node', [ 'xxx.js' ]);
child.stdout.on('data', function (data) {
console.log('stdout: ' + data);
child.stderr.on('data', function (data) {
console.log('stderr: ' + data);
child.on('close', function (code) {
console.log('child process exited with code ' + code);
上例中使用了.spawn(exec, args, options)方法,该方法支持三个参数。第一个参数是执行文件路径,可以是执行文件的相对或绝对路径,也可以是根据PATH环境变量能找到的执行文件名。第二个参数中,数组中的每个成员都按顺序对应一个命令行参数。第三个参数可选,用于配置子进程的执行环境与行为。
另外,上例中虽然通过子进程对象的.stdout和.stderr访问子进程的输出,但通过options.stdio字段的不同配置,可以将子进程的输入输出重定向到任何数据流上,或者让子进程共享父进程的标准输入输出流,或者直接忽略子进程的输入输出。& & NodeJS子进程简介 NodeJS子进程提供了与系统交互的重要接口,其主要API有: 标准输入、标准输出及标准错误输出的接口。& & NodeJS子进程简介& & NodeJS 子进程提供了与系统交互的重要接口,其主要 API 有:& & 标准输……
声明:该文章系网友上传分享,此内容仅代表网友个人经验或观点,不代表本网站立场和观点;若未进行原创声明,则表明该文章系转载自互联网;若该文章内容涉嫌侵权,请及时向
论文写作技巧
上一篇:下一篇:
相关经验教程child_process模块怎么真正的杀死子进程 - CNode技术社区
这家伙很懒,什么个性签名都没有留下。
'use strict';
var spawn = require('child_process').
* normalize exec args
* @param command
* @param options
* @returns {{cmd: *, shell: *, args: *, options: *}}
function normalizeExecArgs(command, options){
var shell,
// Make a shallow copy before patching so we don't clobber the user's
// options object.
options = options || {};
if (process.platform === 'win32') {
shell = spec || 'cmd.exe';
args = ['/s', '/c', '&' + command + '&'];
options.windowsVerbatimArguments =
shell = '/bin/sh';
args = ['-c', command];
if (options.shell) {
shell = options.
shell: shell,
args: args,
options: options
function exec(){
var parsed = normalizeExecArgs.apply(null, arguments);
return spawn(parsed.shell, parsed.args, parsed.options);
var thread = exec('ping
-t', {
env: process.env,
cwd: process.cwd()
thread.stdout.on('data', function (data){
console.log(data.toString());
thread.stderr.on('data', function (error){
console.log(error.toString());
thread.on('close', function (signal){
console.log(signal.toString());
setTimeout(function (){
thread.kill();
// process.kill(thread.pid);
// process.exit();
代码跑起来后thread.kill并不能杀死后台ping进程,结果会一直打印,用process.kill和process.exit也无效,任务管理器
中ping进程还在跑,本来想用electron做个命令管理工具 ,然后现在碰到这个问题计划泡汤,无法结束像ping
-t这样在后台一直跑的命令,前天做测试,没注意到这个问题,结果后台默默的开了100多个ping有木有啊 - -!
我自己做的例子是用的fork,在子进程所运行的文件里写了process.exit();是可以跑起来的,任务管理器的进程数一直是加加减减; 我又试了一下,感觉延迟600也是ok的,我的观点是你可以在事件互动的最末尾监听一个退出事件,子进程监听到这个事件执行退出;所以你这个问题我感觉是同步异步的问题,不知道对不对,请指教
process.exit(0),表示成功
process.exit(err.code),表示失败
以上两个都可以让子进程退出
调用的本地应用,无法process.exit(),换了另一种解决方法:
主进程不能结束,其他方法解决了:
CNode 社区为国内最专业的 Node.js 开源技术社区,致力于 Node.js 的技术研究。
服务器赞助商为
,存储赞助商为
,由提供应用性能服务。
新手搭建 Node.js 服务器,推荐使用无需备案的

我要回帖

更多关于 sb a child wnd 进程 的文章

 

随机推荐