參考資料:
最近在用nodejs 的child_process 模塊調用系統的shell腳本,但是發現遇到一些問題
- child_process.exec 方法調用shell腳本發現內容過長會拋錯 Error: maxBuffer exceeded(和options.maxBuffer有關)
- child_process.spawn 方法調用shell腳本發現控制台無法監聽用戶的輸入(和options. stdio 設置有關)
- nodejs 調用 shell 后,shell里面的命令找不到(和options.env有關)
- nodejs 如何傳入 env 到shell里(和options.env有關)
spawn 和 exec 的區別
總體來說 spawn 返回一個stream,exec返回一個buffer
child_process.spawn 返回一個有輸出流和錯誤的流的對象,你可以監聽它們從而獲取數據,輸出流有數據和結束事件,child_process.spawn 適合用在處理大量數據返回的場景中,圖片處理,讀二進制數據等等。
child_process.spawn是一個異步的異步函數,怎么解釋呢?child_process.spawn 在執行時就會返回數據,而不是等到數據都處理好了再一次返回。
child_process.exec 一次性返回輸出執行結果內容,默認的buffer大小為200kb,如果exec返回的內容超過 200kb則會返回一個錯誤:Error maxBuffer execeded,你可以通過設置options buffer的size來擴大 buffer 的大小。
child_process.exec 是一個同步的異步方法,這個意思是,雖然方法體本身是異步的,但是它要等 child process 執行完成后,再把返回數據一口氣返回給回調方法。如果返回內容超過了設置的buffer size,則會返回一個maxBuffer exceeded 錯誤。
options.stdio
options.stdio 選項用於配置子進程與父進程之間建立的管道。 默認情況下,子進程的 stdin、 stdout 和 stderr 會重定向到 ChildProcess 對象上相應的 child.stdin、 child.stdout 和 child.stderr 流。 這等同於將 options.stdio 設為 ['pipe', 'pipe', 'pipe']。
這個配置不一定是數組,也可以是字符串,
- pipe == [‘pipe', 'pipe', 'pipe']
- ignore == ['ignore', 'ignore', 'ignore']
- inherit == [process.stdin, process.stdout, process.stderr] 流會定向到你系統的bash 環境中,nodejs不再接管錯誤、數據的處理
let ls = spawn('ls', ['-al'], {
stdio: ['pipe', 'pipe', 'pipe']
});
ls.stdout.on('data', (data) => {
console.log(`stdout: ${data}`);
});
ls.stderr.on('data', (data) => {
console.log(`stderr: ${data}`);
});
ls.on('close', (code) => {
console.log(`子進程退出碼:${code}`);
});
這種情況下,子進程的數據會返回給父進程,也就是nodejs,然后你可以監聽流的輸出。
設置 stdio 為 ‘inherit’
let ls = spawn('ls', ['-al'], {
stdio: ['inherit', 'inherit', 'inherit']
});
ls.stdout.on('data', (data) => {
console.log(`stdout: ${data}`);
});
會拋出錯誤,
ls.stdout.on('data', (data) => {
^
TypeError: Cannot read property 'on' of null
但是你在控制台應該可以看到數據,這個數據是bash執行的結果
傳入shell的環境變量
使用 options.env 可以傳入變量,在 shell中可以直接使用。
test_shell.js
#! /bin/bash
echo $NAME
test_child_process.js
let spawn = require("child_process").spawn;
let options = {
stdio: 'inherit',
env: Object.assign({NAME: "cowboy"}, process.env)
}
spawn('sh', ['./test_shell.sh'], options);
輸出
cowboy