NodeJs 子程序child_process
child_process
模組提供了以與 popen(3)
類似但不完全相同的方式衍生子程序的能力。 此功能主要由 child_process.spawn()
函式提供:
1. spawn
child_process.spawn()
方法使用給定的command
和args
中的命令列引數衍生新程序。 如果省略,args
預設為空陣列。
如果啟用了shell
選項,則請勿將未經處理的使用者輸入傳遞給此函式。 任何包含 shell 元字元的輸入都可用於觸發任意命令執行。
-
command
<string>要執行的命令。 -
args
<string[]>字串引數列表。 -
options
cwd
<string>|<URL>子程序的當前工作目錄。env
<Object>環境變數鍵值對。預設值:process.env
。argv0
<string>顯式設定傳送給子程序的argv[0]
的值。 如果未指定,這將設定為command
。stdio
<Array>|<string>子程序的標準輸入輸出配置(參見options.stdio
)。detached
<boolean>準備子程序獨立於其父程序執行。 具體行為取決於平臺,參見options.detached
。uid
<number>setuid(2)
)。gid
<number>設定程序的群組標識(參見setgid(2)
)。serialization
<string>指定用於在程序之間傳送訊息的序列化型別。 可能的值為'json'
和'advanced'
。 有關更多詳細資訊,請參閱高階序列化。預設值:'json'
。shell
<boolean>|<string>如果是true
,則在 shell 內執行command
。 在 Unix 上使用'/bin/sh'
,在 Windows 上使用process.env.ComSpec
。 可以將不同的 shell 指定為字串。 請參閱false
(沒有 shell)windowsVerbatimArguments
<boolean>在 Windows 上不為引數加上引號或轉義。 在 Unix 上被忽略。 當指定了shell
並且是 CMD 時,則自動設定為true
。預設值:false
。windowsHide
<boolean>隱藏通常在 Windows 系統上建立的子程序控制檯視窗。預設值:false
。signal
<AbortSignal>允許使用中止訊號中止子程序。timeout
<number>允許程序執行的最長時間(以毫秒為單位)。預設值:undefined
。killSignal
<string>|<integer>當衍生的程序將被超時或中止訊號殺死時要使用的訊號值。預設值:'SIGTERM'
。
對於其它的方法,引數類似
1 const ps = child.spawn('ps', ['ax']); 2 const grep = child.spawn('grep', ['ssh']); 3 4 ps.stdout.on('data', (data) => { 5 grep.stdin.write(data); 6 }); 7 8 ps.stderr.on('data', (data) => { 9 console.error(`ps stderr: ${data}`); 10 }); 11 12 ps.on('close', (code) => { 13 if (code !== 0) { 14 console.log(`ps process exited with code ${code}`); 15 } 16 grep.stdin.end(); 17 }); 18 19 grep.stdout.on('data', (data) => { 20 console.log(data.toString()); 21 }); 22 23 grep.stderr.on('data', (data) => { 24 console.error(`grep stderr: ${data}`); 25 }); 26 27 grep.on('close', (code) => { 28 if (code !== 0) { 29 console.log(`grep process exited with code ${code}`); 30 } 31 });
2. exec
和spawn功能類似,用於另開程序啟動shell命令。
child_process.exec()
不替換現有程序,而是使用 shell 來執行命令。
舉例:讓其用ts-node直接執行typescript程式碼
1 import * as child from 'child_process'; 2 3 child.exec('ts-node child.ts 1', ((error, stdout, stderr) => { 4 if (error) { 5 console.error(error); 6 return; 7 } 8 console.log(stdout); 9 }));
3. execfile
和exec類似,不同之處在於它預設不衍生 shell。 而是,指定的可執行檔案file
直接作為新程序衍生,使其比child_process.exec()
略有效率。
有args引數可以傳型別為Array[string]的引數
1 import * as child from 'child_process'; 2 3 child.execFile('ts-node', ['child.ts'], ((error, stdout, stderr) => { 4 if (error) { 5 console.error(error); 6 return; 7 } 8 console.log(stdout); 9 }));
4. fork
用於另開程序執行javascript指令碼,直接傳js路徑
1 import * as child from 'child_process'; 2 3 const c1 = child.fork('child.js', ['2'], { 4 silent: false, 5 }); 6 7 const c2 = child.fork('child.js',['3'], { 8 silent: false, 9 });
5. sync
每個方法都有對應的sync版本,nodejs執行時會阻塞直至子程序完全退出
6. 事件
'close'
事件
在程序已結束並且子程序的標準輸入輸出流已關閉之後,則觸發'close'
事件。 這與'exit'
事件不同,因為多個程序可能共享相同的標準輸入輸出流。'close'
事件將始終在'exit'
或'error'
(如果子程序衍生失敗)已經觸發之後觸發。
const { spawn } = require('child_process');
const ls = spawn('ls', ['-lh', '/usr']);
ls.stdout.on('data', (data) => {
console.log(`stdout: ${data}`);
});
ls.on('close', (code) => {
console.log(`child process close all stdio with code ${code}`);
});
ls.on('exit', (code) => {
console.log(`child process exited with code ${code}`);
});
'disconnect'
事件
呼叫父程序中的subprocess.disconnect()
方法或子程序中的process.disconnect()
方法後會觸發'disconnect'
事件。 斷開連線後就不能再發送或接收訊息,且subprocess.connected
屬性為false
。
'error'
事件
'error'
事件在以下情況下觸發:
- 無法衍生該程序,或
- 程序無法終止,或
- 向子程序傳送訊息失敗。
發生錯誤後,'exit'
事件可能會也可能不會觸發。 在監聽'exit'
和'error'
事件時,防止多次意外呼叫控制代碼函式。
另見subprocess.kill()
和subprocess.send()
。
'exit'
事件
'exit'
事件在子程序結束後觸發。 如果程序退出,則code
為最終的程序退出碼,否則為null
。 如果程序因收到訊號而終止,則signal
是訊號的字串名稱,否則為null
。 兩者之一將始終是非null
。
當'exit'
事件被觸發時,子程序標準輸入輸出流可能仍處於開啟狀態。
Node.js 為SIGINT
和SIGTERM
建立訊號控制代碼,且 Node.js 程序不會因為收到這些訊號而立即終止。 而是,Node.js 將執行一系列清理操作,然後重新觸發已處理的訊號。
參見waitpid(2)
。
'message'
事件
message
<Object>解析的 JSON 物件或原始值。sendHandle
<Handle>net.Socket
或net.Server
物件、或未定義。
當子程序使用process.send()
傳送訊息時,則觸發'message'
事件。
訊息經過序列化和解析。 結果訊息可能與最初發送的訊息不同。
如果在衍生子程序時將serialization
選項設定為'advanced'
,則message
引數可以包含 JSON 無法表示的資料。 有關更多詳細資訊,請參閱高階序列化。
'spawn'
事件
一旦子程序衍生成功,則會觸發'spawn'
事件。 如果子程序沒有衍生成功,則不會觸發'spawn'
事件,而是觸發'error'
事件。
如果觸發,則'spawn'
事件在所有其他事件之前,且在通過stdout
或stderr
接收任何資料之前。
無論在衍生的程序內是否發生錯誤,'spawn'
事件都會觸發。 例如,如果bash some-command
衍生成功,則'spawn'
事件將觸發,儘管bash
可能衍生some-command
失敗。 當使用{ shell: true }
時,此注意事項也適用。