來自《JavaScript 標準參考教程(alpha)》,by 阮一峯javascript
child_process模塊用於新建子進程。子進程的運行結果儲存在系統緩存之中(最大200KB),等到子進程運行結束之後,主進程再用回調函數讀取子進程的運行結果。html
exec
方法用於執行bash命令,它的參數是一個命令字符串。java
var exec = require('child_process').exec; var ls = exec('ls -l', function (error, stdout, stderr) { if (error) { console.log(error.stack); console.log('Error code: ' + error.code); } console.log('Child Process STDOUT: ' + stdout); });
上面代碼的exec
方法用於新建一個子進程,而後緩存它的運行結果,運行結束後調用回調函數。node
exec
方法最多能夠接受兩個參數,第一個參數是所要執行的shell命令,第二個參數是回調函數,該函數接受三個參數,分別是發生的錯誤、標準輸出的顯示結果、標準錯誤的顯示結果。git
因爲標準輸出和標準錯誤都是流對象(stream),能夠監聽data事件,所以上面的代碼也能夠寫成下面這樣。github
var exec = require('child_process').exec; var child = exec('ls -l'); child.stdout.on('data', function(data) { console.log('stdout: ' + data); }); child.stderr.on('data', function(data) { console.log('stdout: ' + data); }); child.on('close', function(code) { console.log('closing code: ' + code); });
上面的代碼還代表,子進程自己有close
事件,能夠設置回調函數。shell
上面的代碼還有一個好處。監聽data事件之後,能夠實時輸出結果,不然只有等到子進程結束,纔會輸出結果。因此,若是子進程運行時間較長,或者是持續運行,第二種寫法更好。數組
下面是另外一個例子,假定有一個child.js文件。緩存
// child.js var exec = require('child_process').exec; exec('node -v', function(error, stdout, stderr) { console.log('stdout: ' + stdout); console.log('stderr: ' + stderr); if (error !== null) { console.log('exec error: ' + error); } });
運行後,該文件的輸出結果以下。安全
$ node child.js stdout: v0.11.14 stderr:
exec方法會直接調用bash(/bin/sh
程序)來解釋命令,因此若是有用戶輸入的參數,exec方法是不安全的。
var path = ";user input"; child_process.exec('ls -l ' + path, function (err, data) { console.log(data); });
上面代碼表示,在bash環境下,ls -l; user input
會直接運行。若是用戶輸入惡意代碼,將會帶來安全風險。所以,在有用戶輸入的狀況下,最好不使用exec
方法,而是使用execFile
方法。
execSync
是exec
的同步執行版本。
它能夠接受兩個參數,第一個參數是所要執行的命令,第二個參數用來配置執行環境。
var execSync = require("child_process").execSync; var SEPARATOR = process.platform === 'win32' ? ';' : ':'; var env = Object.assign({}, process.env); env.PATH = path.resolve('./node_modules/.bin') + SEPARATOR + env.PATH; function myExecSync(cmd) { var output = execSync(cmd, { cwd: process.cwd(), env: env }); console.log(output); } myExecSync('eslint .');
上面代碼中,execSync
方法的第二個參數是一個對象。該對象的cwd
屬性指定腳本的當前目錄,env
屬性指定環境變量。上面代碼將./node_modules/.bin
目錄,存入$PATH
變量。這樣就能夠不加路徑,引用項目內部的模塊命令了,好比eslint
命令實際執行的是./node_modules/.bin/eslint
。
execFile方法直接執行特定的程序,參數做爲數組傳入,不會被bash解釋,所以具備較高的安全性。
var child_process = require('child_process'); var path = "."; child_process.execFile('/bin/ls', ['-l', path], function (err, result) { console.log(result) });
上面代碼中,假定path
來自用戶輸入,若是其中包含了分號或反引號,ls程序不理解它們的含義,所以也就得不到運行結果,安全性就獲得了提升。
spawn方法建立一個子進程來執行特定命令,用法與execFile方法相似,可是沒有回調函數,只能經過監聽事件,來獲取運行結果。它屬於異步執行,適用於子進程長時間運行的狀況。
var child_process = require('child_process'); var path = '.'; var ls = child_process.spawn('/bin/ls', ['-l', path]); ls.stdout.on('data', function (data) { console.log('stdout: ' + data); }); ls.stderr.on('data', function (data) { console.log('stderr: ' + data); }); ls.on('close', function (code) { console.log('child process exited with code ' + code); });
spawn方法接受兩個參數,第一個是可執行文件,第二個是參數數組。
spawn對象返回一個對象,表明子進程。該對象部署了EventEmitter接口,它的data
事件能夠監聽,從而獲得子進程的輸出結果。
spawn方法與exec方法很是相似,只是使用格式略有區別。
child_process.exec(command, [options], callback) child_process.spawn(command, [args], [options])
fork方法直接建立一個子進程,執行Node腳本,fork('./child.js')
至關於 spawn('node', ['./child.js'])
。與spawn方法不一樣的是,fork會在父進程與子進程之間,創建一個通訊管道,用於進程之間的通訊。
var n = child_process.fork('./child.js'); n.on('message', function(m) { console.log('PARENT got message:', m); }); n.send({ hello: 'world' });
上面代碼中,fork方法返回一個表明進程間通訊管道的對象,對該對象能夠監聽message事件,用來獲取子進程返回的信息,也能夠向子進程發送信息。
child.js腳本的內容以下。
process.on('message', function(m) { console.log('CHILD got message:', m); }); process.send({ foo: 'bar' });
上面代碼中,子進程監聽message事件,並向父進程發送信息。
使用 child_process.fork() 生成新進程以後,就能夠用 child.send(message, [sendHandle]) 向新進程發送消息。新進程中經過監聽message事件,來獲取消息。
下面的例子是主進程的代碼。
var cp = require('child_process'); var n = cp.fork(__dirname + '/sub.js'); n.on('message', function(m) { console.log('PARENT got message:', m); }); n.send({ hello: 'world' });
下面是子進程sub.js代碼。
process.on('message', function(m) { console.log('CHILD got message:', m); }); process.send({ foo: 'bar' });
| last modified on 2014-05-24