io.js
通過child_process
模塊提供了三向的popen
功能。
可以無阻塞地通過子進(jìn)程的stdin
,stdout
和stderr
以流的方式傳遞數(shù)據(jù)。(注意某些程序在內(nèi)部使用了行緩沖I/O,這不會影響io.js
,但是這意味你傳遞給子進(jìn)程的數(shù)據(jù)可能不會在第一時(shí)間被消費(fèi))。
可以通過require('child_process').spawn()
或require('child_process').fork()
創(chuàng)建子進(jìn)程。這兩者間的語義有少許差別,將會在后面進(jìn)行解釋。
當(dāng)以寫腳本為目的時(shí),你可以會覺得使用同步版本的方法會更方便。
ChildProcess
是一個(gè)EventEmitter
。
子進(jìn)程總是有三個(gè)與之相關(guān)的流。child.stdin
,child.stdout
和child.stderr
。他們可能會共享父進(jìn)程的stdio流,或者也可以是獨(dú)立的被導(dǎo)流的流對象。
ChildProcess
類并不是用來直接被使用的。應(yīng)當(dāng)使用spawn()
,exec()
,execFile()
或fork()
方法來創(chuàng)建一個(gè)子進(jìn)程實(shí)例。
發(fā)生于:
進(jìn)程不能被創(chuàng)建時(shí),進(jìn)程不能殺死時(shí),給子進(jìn)程發(fā)送信息失敗時(shí)。注意exit
事件在一個(gè)錯(cuò)誤發(fā)生后可能觸發(fā)。如果你同時(shí)監(jiān)聽了這兩個(gè)事件來觸發(fā)一個(gè)函數(shù),需要記住不要讓這個(gè)函數(shù)被觸發(fā)兩次。
參閱 ChildProcess.kill()
和 ChildProcess.send()
。
注意子進(jìn)程的stdio流可能仍為打開狀態(tài)。
還需要注意的是,io.js
已經(jīng)為我們添加了'SIGINT'信號和'SIGTERM'信號的事件處理函數(shù),所以在父進(jìn)程發(fā)出這兩個(gè)信號時(shí),進(jìn)程將會退出。
參閱 waitpid(2)
。
stdio
流都關(guān)閉時(shí)觸發(fā)。這是與exit
的區(qū)別,因?yàn)榭赡軙袔讉€(gè)進(jìn)程共享同樣的stdio
流。在父進(jìn)程或子進(jìn)程中使用.disconnect()
方法后這個(gè)事件會觸發(fā)。在斷開之后,將不能繼續(xù)相互發(fā)送信息,并且子進(jìn)程的.connected
屬性將會是false
。
Socket
或Server
對象通過.send(message, [sendHandle])
發(fā)送的信息可以通過監(jiān)聽message
事件獲取到。
一個(gè)代表了子進(jìn)程的stdin
的可寫流。通過end()
方法關(guān)閉此流可以終止子進(jìn)程。
如果子進(jìn)程通過spawn
創(chuàng)建時(shí)stdio
沒有被設(shè)置為pipe
,那么它將不會被創(chuàng)建。
child.stdin
為child.stdio
中對應(yīng)元素的快捷引用。它們要么都指向同一個(gè)對象,要么都為null。
一個(gè)代表了子進(jìn)程的stdout
的可讀流。
如果子進(jìn)程通過spawn
創(chuàng)建時(shí)stdio
沒有被設(shè)置為pipe
,那么它將不會被創(chuàng)建。
child.stdout
為child.stdio
中對應(yīng)元素的快捷引用。它們要么都指向同一個(gè)對象,要么都為null。
一個(gè)代表了子進(jìn)程的stderr
的可讀流。
如果子進(jìn)程通過spawn
創(chuàng)建時(shí)stdio
沒有被設(shè)置為pipe
,那么它將不會被創(chuàng)建。
child.stderr
為child.stdio
中對應(yīng)元素的快捷引用。它們要么都指向同一個(gè)對象,要么都為null。
一個(gè)包含了子進(jìn)程的管道的稀疏數(shù)組,元素的位置對應(yīng)著利用spawn
創(chuàng)建子進(jìn)程時(shí)stdio
配置參數(shù)里被設(shè)置為pipe
的位置。注意索引為0-2的流分別與ChildProcess.stdin
, ChildProcess.stdout
和ChildProcess.stderr
引用的是相同的對象。
在下面的例子中,在stdio
參數(shù)中只有索引為1的元素被設(shè)置為了pipe
,所以父進(jìn)程中只有child.stdio[1]
是一個(gè)流,其他的元素都為null
。
var assert = require('assert');
var fs = require('fs');
var child_process = require('child_process');
child = child_process.spawn('ls', {
stdio: [
0, // use parents stdin for child
'pipe', // pipe child's stdout to parent
fs.openSync('err.out', 'w') // direct child's stderr to a file
]
});
assert.equal(child.stdio[0], null);
assert.equal(child.stdio[0], child.stdin);
assert(child.stdout);
assert.equal(child.stdio[1], child.stdout);
assert.equal(child.stdio[2], null);
assert.equal(child.stdio[2], child.stderr);
子進(jìn)程的PID
。
例子:
var spawn = require('child_process').spawn,
grep = spawn('grep', ['ssh']);
console.log('Spawned child pid: ' + grep.pid);
grep.stdin.end();
.disconnect
方法被調(diào)用后將會被設(shè)置為false
。如果.connected
屬性為false
,那么將不能再向子進(jìn)程發(fā)送信息。給子進(jìn)程傳遞一個(gè)信號。如果沒有指定任何參數(shù),那么將發(fā)送'SIGTERM'
給子進(jìn)程。更多可用的信號請參閱signal(7)
。
var spawn = require('child_process').spawn,
grep = spawn('grep', ['ssh']);
grep.on('close', function (code, signal) {
console.log('child process terminated due to receipt of signal ' + signal);
});
// send SIGHUP to process
grep.kill('SIGHUP');
在信號不能被送達(dá)時(shí),可能會產(chǎn)生一個(gè)error
事件。給一個(gè)已經(jīng)終止的子進(jìn)程發(fā)送一個(gè)信號不會發(fā)生錯(cuò)誤,但可以操作不可預(yù)料的后果:如果該子進(jìn)程的PID
已經(jīng)被重新分配給了另一個(gè)進(jìn)程,那么這個(gè)信號會被傳遞到另一個(gè)進(jìn)程中。大家可以猜想這將會發(fā)生什么樣的情況。
注意這個(gè)函數(shù)僅僅是名字叫kill,給子進(jìn)程發(fā)送的信號可能不是去關(guān)閉它的。這個(gè)函數(shù)僅僅只是給子進(jìn)程發(fā)送一個(gè)信號。
參閱kill(2)
。
當(dāng)使用child_process.fork()
時(shí),你可以使用child.send(message, [sendHandle])
向子進(jìn)程發(fā)送信息,子進(jìn)程里會觸發(fā)message
事件當(dāng)收到信息時(shí)。
例子:
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' });
子進(jìn)程代碼, sub.js
可能看起來類似這樣:
process.on('message', function(m) {
console.log('CHILD got message:', m);
});
process.send({ foo: 'bar' });
在子進(jìn)程中,process
對象將有一個(gè)send()
方法,在它的信道上收到一個(gè)信息時(shí),信息將以對象的形式返回。
請注意父進(jìn)程,子進(jìn)程中的send()
方法都是同步的,所以發(fā)送大量數(shù)據(jù)是不被建議的(可以使用管道代替,參閱child_process.spawn
)。
發(fā)送{cmd: 'NODE_foo'}
信息時(shí)是一個(gè)特殊情況。所有的在cmd
屬性中包含了NODE_
前綴的信息都不會觸發(fā)message
事件,因?yàn)檫@是io.js
內(nèi)核使用的內(nèi)部信息。包含這個(gè)前綴的信息都會觸發(fā)internalMessage
事件。請避免使用這個(gè)事件,它在改變的時(shí)候不會收到通知。
child.send()
的sendHandle
參數(shù)時(shí)用來給另一個(gè)進(jìn)程發(fā)送一個(gè)TCP服務(wù)器
或一個(gè)socket
的。將之作為第二個(gè)參數(shù)傳入,子進(jìn)程將在message
事件中會收到這個(gè)對象。
如果信息不能被發(fā)送的話將會觸發(fā)一個(gè)error
事件,比如子進(jìn)程已經(jīng)退出了。
例子:發(fā)送一個(gè)server
對象
var child = require('child_process').fork('child.js');
// Open up the server object and send the handle.
var server = require('net').createServer();
server.on('connection', function (socket) {
socket.end('handled by parent');
});
server.listen(1337, function() {
child.send('server', server);
});
子進(jìn)程將會收到server
對象:
process.on('message', function(m, server) {
if (m === 'server') {
server.on('connection', function (socket) {
socket.end('handled by child');
});
}
});
注意這個(gè)server
現(xiàn)在已經(jīng)被父進(jìn)程和子進(jìn)程所共享,這意味著鏈接將可能被父進(jìn)程處理也可能被子進(jìn)程處理。
對于dgram
服務(wù)器,流程也是完全一樣的。使用message
事件而不是connection
事件,使用server.bind
問不是server.listen
(目前只支持UNIX
平臺)。
例子:發(fā)送一個(gè)socket
對象
以下是發(fā)送一個(gè)socket
的例子。創(chuàng)建了兩個(gè)子進(jìn)程。并且將地址為74.125.127.100
的鏈接通過將socket
發(fā)送給"special"子進(jìn)程來視作VIP。其他的socket
則被發(fā)送給"normal"子進(jìn)程。
var normal = require('child_process').fork('child.js', ['normal']);
var special = require('child_process').fork('child.js', ['special']);
// Open up the server and send sockets to child
var server = require('net').createServer();
server.on('connection', function (socket) {
// if this is a VIP
if (socket.remoteAddress === '74.125.127.100') {
special.send('socket', socket);
return;
}
// just the usual dudes
normal.send('socket', socket);
});
server.listen(1337);
`child.js`:
```js
process.on('message', function(m, socket) {
if (m === 'socket') {
socket.end('You were handled as a ' + process.argv[2] + ' person');
}
});
注意一旦一個(gè)單獨(dú)的socket
被發(fā)送給了子進(jìn)程,那么父進(jìn)程將不能追蹤到這個(gè)socket
被刪除的時(shí)間,這個(gè)情況下.connections
屬性將會成為null
。在這個(gè)情況下同樣也不推薦使用.maxConnections
屬性。
關(guān)閉父進(jìn)程與子進(jìn)程間的IPC信道,它讓子進(jìn)程非常優(yōu)雅地退出,因?yàn)橐呀?jīng)活躍的信道了。在調(diào)用了這個(gè)方法后,父進(jìn)程和子進(jìn)程的.connected
標(biāo)簽都會被設(shè)置為false
,將不能再發(fā)送信息。
disconnect
事件在進(jìn)程不再有消息接收時(shí)觸發(fā)。
注意,當(dāng)子進(jìn)程中有與父進(jìn)程通信的IPC信道時(shí),你也可以在子進(jìn)程中調(diào)用process.disconnect()
。
以下方法遵循普遍的異步編程模式(接受一個(gè)回調(diào)函數(shù)或返回一個(gè)EventEmitter
)。
args Array 字符串參數(shù)數(shù)組
options Object
gid Number 設(shè)置進(jìn)程組的ID
return: ChildProcess object
利用給定的命令以及參數(shù)執(zhí)行一個(gè)新的進(jìn)程,如果沒有參數(shù)數(shù)組,那么args
將默認(rèn)是一個(gè)空數(shù)組。
第三個(gè)參數(shù)時(shí)用來指定以為額外的配置,以下是它的默認(rèn)值:
{ cwd: undefined,
env: process.env
}
使用cwd
來指定子進(jìn)程的工作目錄。如果沒有指定,默認(rèn)值是當(dāng)前父進(jìn)程的工作目錄。
使用env
來指定子進(jìn)程中可用的環(huán)境變量,默認(rèn)值是process.env
。
Example of running ls -lh /usr, capturing stdout, stderr, and the exit code:一個(gè)運(yùn)行ls -lh /usr
,獲取stdout
,stderr
和退出碼得例子:
var spawn = require('child_process').spawn,
ls = spawn('ls', ['-lh', '/usr']);
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);
});
例子:一個(gè)非常精巧的運(yùn)行ps ax | grep ssh
的方式
var spawn = require('child_process').spawn,
ps = spawn('ps', ['ax']),
grep = spawn('grep', ['ssh']);
ps.stdout.on('data', function (data) {
grep.stdin.write(data);
});
ps.stderr.on('data', function (data) {
console.log('ps stderr: ' + data);
});
ps.on('close', function (code) {
if (code !== 0) {
console.log('ps process exited with code ' + code);
}
grep.stdin.end();
});
grep.stdout.on('data', function (data) {
console.log('' + data);
});
grep.stderr.on('data', function (data) {
console.log('grep stderr: ' + data);
});
grep.on('close', function (code) {
if (code !== 0) {
console.log('grep process exited with code ' + code);
}
});
一個(gè)檢查執(zhí)行失敗的例子:
var spawn = require('child_process').spawn,
child = spawn('bad_command');
child.on('error', function (err) {
console.log('Failed to start child process.');
});
作為快捷方式,stdio
的值可以是一下字符串之一:
'pipe' - ['pipe', 'pipe', 'pipe'], 這是默認(rèn)值'ignore' - ['ignore', 'ignore', 'ignore']'inherit' - [process.stdin, process.stdout, process.stderr]或[0,1,2]
否則,child_process.spawn()
的stdio
參數(shù)時(shí)一個(gè)數(shù)組,數(shù)組中的每一個(gè)索引的對應(yīng)子進(jìn)程中的一個(gè)文件標(biāo)識符??梢允窍铝兄抵唬?/p>
'pipe' - 創(chuàng)建一個(gè)子進(jìn)程與父進(jìn)程之間的管道,管道的父進(jìn)程端已父進(jìn)程的child_process
對象的屬性(ChildProcess.stdio[fd]
)暴露給父進(jìn)程。為文件表示(fds)0 - 2 創(chuàng)建的管道也可以通過ChildProcess.stdin
,ChildProcess.stdout
和ChildProcess.stderr
分別訪問。
'ipc' - 創(chuàng)建一個(gè)子進(jìn)程和父進(jìn)程間 傳輸信息/文件描述符 的IPC信道。一個(gè)子進(jìn)程最多可能有一個(gè)IPC stdio 文件描述符。設(shè)置該選項(xiàng)將激活ChildProcess.send()
方法。如果子進(jìn)程向此文件描述符中寫入JSON數(shù)據(jù),則會觸發(fā)ChildProcess.on('message')
。如果子進(jìn)程是一個(gè)io.js
程序,那么IPC信道的存在將會激活process.send()
和process.on('message')
。
'ignore' - 不在子進(jìn)程中設(shè)置文件描述符。注意io.js
總是會為通過spawn
創(chuàng)建的子進(jìn)程打開文件描述符(fd) 0 - 2。如果這其中任意一項(xiàng)被設(shè)置為了ignore
,io.js
會打開/dev/null
并將其附給子進(jìn)程對應(yīng)的文件描述符(fd)。
Stream object - 與子進(jìn)程共享一個(gè)與tty,文件,socket,或管道相關(guān)的可讀/可寫流。該流底層(underlying)的文件標(biāo)識在子進(jìn)程中被復(fù)制給stdio數(shù)組索引對應(yīng)的文件描述符(fd)。
Positive integer - 該整形值被解釋為父進(jìn)程中打開的文件標(biāo)識符。他與子進(jìn)程共享,和Stream被共享的方式相似。
null, undefined - 使用默認(rèn)值。For 對于stdio fds 0,1,2(或者說stdin
,stdout
和stderr
),pipe管道被建立。對于fd 3及往后,默認(rèn)為ignore
。
例子:
var spawn = require('child_process').spawn;
// Child will use parent's stdios
spawn('prg', [], { stdio: 'inherit' });
// Spawn child sharing only stderr
spawn('prg', [], { stdio: ['pipe', 'pipe', process.stderr] });
// Open an extra fd=4, to interact with programs present a
// startd-style interface.
spawn('prg', [], { stdio: ['pipe', null, null, null, 'pipe'] });
如果detached
選項(xiàng)被設(shè)置,子進(jìn)程將成為新進(jìn)程組的領(lǐng)導(dǎo)。這使得在父進(jìn)程退出后,子進(jìn)程繼續(xù)執(zhí)行成為可能。
默認(rèn)情況下,父進(jìn)程會等待脫離了的子進(jìn)程退出。要阻止父進(jìn)程等待一個(gè)給出的子進(jìn)程,請使用child.unref()
方法,則父進(jìn)程的事件循環(huán)的計(jì)數(shù)中將不包含這個(gè)子進(jìn)程。
一個(gè)脫離的長時(shí)間運(yùn)行的進(jìn)程,以及將它的輸出重定向到文件中的例子:
var fs = require('fs'),
spawn = require('child_process').spawn,
out = fs.openSync('./out.log', 'a'),
err = fs.openSync('./out.log', 'a');
var child = spawn('prg', [], {
detached: true,
stdio: [ 'ignore', out, err ]
});
child.unref();
當(dāng)使用detached
選項(xiàng)創(chuàng)建一個(gè)長時(shí)間運(yùn)行的進(jìn)程時(shí),進(jìn)程不會保持運(yùn)行除非向它提供了一個(gè)不連接到父進(jìn)程的stdio
的配置。如果繼承了父進(jìn)程的stdio
,那么子進(jìn)程將會繼續(xù)附著在控制終端。
參閱: child_process.exec()
和 child_process.fork()
command String 將要運(yùn)行的命令,參數(shù)使用空格隔開
options Object
/bin/sh
, 在Windows中為cmd.exe
, Shell應(yīng)當(dāng)能識別 -c
開關(guān)在UNIX中,或 /s /c
在Windows中。 在Windows中,命令行解析應(yīng)當(dāng)能兼容cmd.exe
)gid Number 設(shè)置進(jìn)程組的ID
callback Function
stderr Buffer
在Shell中運(yùn)行一個(gè)命令,并緩存命令的輸出。
var exec = require('child_process').exec,
child;
child = exec('cat *.js bad_file | wc -l',
function (error, stdout, stderr) {
console.log('stdout: ' + stdout);
console.log('stderr: ' + stderr);
if (error !== null) {
console.log('exec error: ' + error);
}
});
回調(diào)函數(shù)的參數(shù)是error
,stdout
,stderr
。在成功時(shí),error
將會是null
。在發(fā)生錯(cuò)誤時(shí),error
將會是一個(gè)Error
實(shí)例,error.code
將會是子進(jìn)程的退出碼,error.signal
將會被設(shè)置為結(jié)束進(jìn)程的信號。
第二個(gè)可選的參數(shù)用于指定一些配置,默認(rèn)值為:
{ encoding: 'utf8',
timeout: 0,
maxBuffer: 200*1024,
killSignal: 'SIGTERM',
cwd: null,
env: null }
如果timeout
大于0,那么子進(jìn)程在運(yùn)行時(shí)超過timeout
時(shí)將會被殺死。子進(jìn)程使用killSignal
信號結(jié)束(默認(rèn)為: 'SIGTERM')。maxBuffer
指定了stdout
,stderr
中的最大數(shù)據(jù)量(字節(jié)),如果超過了這個(gè)數(shù)據(jù)量子進(jìn)程也會被殺死。
注意:不像POSIX中的exec()
,child_process.exec()
不替換已經(jīng)存在的進(jìn)程并且使用一個(gè)SHELL去執(zhí)行命令。
args 字符串參數(shù)數(shù)組
options Object-cwd String 子進(jìn)程的當(dāng)前工作目錄-env Object 環(huán)境變量鍵值對
gid Number 設(shè)置進(jìn)程組的ID
callback Function
stderr Buffer
Return: ChildProcess object
這個(gè)方法和child_process.exec()
相似,除了它不是使用一個(gè)子SHELL執(zhí)行命令而是直接執(zhí)行文件。因此它比child_process.exec
稍許精簡一些。它們有相同的配置。
args Array 字符串參數(shù)數(shù)組
options Object
true
,子進(jìn)程的stdin
,stdout
和stderr
將會被關(guān)聯(lián)至父進(jìn)程,否則,它們將會從父進(jìn)程中繼承。(默認(rèn)為:false
)Return: ChildProcess object
這個(gè)方法是spawn()
的特殊形式,用于創(chuàng)建io.js
進(jìn)程。返回的對象除了擁有ChildProcess
實(shí)例的所有方法,還有一個(gè)內(nèi)建的通信信道。詳情參閱child.send(message, [sendHandle])
。
這些io.js
子進(jìn)程都是全新的V8實(shí)例。每個(gè)新的io.js
進(jìn)程都至少需要30ms啟動以及10mb的內(nèi)存。所以,你不能無休止地創(chuàng)建它們。
options
對象中的execPath
屬性可以用非當(dāng)前io.js
可執(zhí)行文件來創(chuàng)建子進(jìn)程。這需要小心使用,并且缺省情況下會使用子進(jìn)程上的NODE_CHANNEL_FD
環(huán)境變量所指定的文件描述符來通訊。該文件描述符的輸入和輸出假定為以行分割的JSON對象。
注意:不像POSIX中的fork()
,child_process.fork()
不會復(fù)制當(dāng)前進(jìn)程。
以下這些方法是同步的,意味著它們會阻塞事件循環(huán)。直到被創(chuàng)建的進(jìn)程退出前,代碼都將停止執(zhí)行。
這些同步方法對簡化大多數(shù)腳本任務(wù)都十分有用,并對簡化應(yīng)用配置的加載/執(zhí)行也之分有用。
args Array 字符串參數(shù)數(shù)組
options Object
stdin
傳入被創(chuàng)建的進(jìn)程的值,提供這個(gè)值將會覆蓋stdio[0]
stdio
配置undefined
)encoding String 被用于所有stdio
輸入和輸出的編碼(默認(rèn):'buffer')
return: Object
stdio
輸出結(jié)果的數(shù)組stdout
的內(nèi)容stderr
的內(nèi)容spawnSync
會在子進(jìn)程完全結(jié)束后才返回。當(dāng)運(yùn)行超時(shí)或被傳遞killSignal
時(shí),這個(gè)方法會等到進(jìn)程完全退出才返回。也就是說,如果子進(jìn)程處理了SIGTERM
信號并且沒有退出,你的父進(jìn)程會繼續(xù)阻塞。
args Array 字符串參數(shù)數(shù)組
options Object
stdin
傳入被創(chuàng)建的進(jìn)程的值,提供這個(gè)值將會覆蓋stdio[0]
stdio
配置(默認(rèn): 'pipe'),stderr
默認(rèn)得將會輸出到父進(jìn)程的stderr
,除非指定了stdio
undefined
)encoding String 被用于所有stdio
輸入和輸出的編碼(默認(rèn):'buffer')
return: Buffer|String 此命令的stdout
execFileSync
會在子進(jìn)程完全結(jié)束后才返回。當(dāng)運(yùn)行超時(shí)或被傳遞killSignal
時(shí),這個(gè)方法會等到進(jìn)程完全退出才返回。也就是說,如果子進(jìn)程處理了SIGTERM
信號并且沒有退出,你的父進(jìn)程會繼續(xù)阻塞。
如果子進(jìn)程超時(shí)或有一個(gè)非零的狀態(tài)碼,這個(gè)方法會拋出一個(gè)錯(cuò)誤。這個(gè)錯(cuò)誤對象與child_process.spawnSync
的錯(cuò)誤對象相同。
command 將要運(yùn)行的命令
options Object
stdin
傳入被創(chuàng)建的進(jìn)程的值,提供這個(gè)值將會覆蓋stdio[0]
stdio
配置(默認(rèn): 'pipe'),stderr
默認(rèn)得將會輸出到父進(jìn)程的stderr
,除非指定了stdio
undefined
)encoding String 被用于所有stdio
輸入和輸出的編碼(默認(rèn):'buffer')
return: Buffer|String 此命令的stdout
execSync
會在子進(jìn)程完全結(jié)束后才返回。當(dāng)運(yùn)行超時(shí)或被傳遞killSignal
時(shí),這個(gè)方法會等到進(jìn)程完全退出才返回。也就是說,如果子進(jìn)程處理了SIGTERM
信號并且沒有退出,你的父進(jìn)程會繼續(xù)阻塞。
如果子進(jìn)程超時(shí)或有一個(gè)非零的狀態(tài)碼,這個(gè)方法會拋出一個(gè)錯(cuò)誤。這個(gè)錯(cuò)誤對象與child_process.spawnSync
的錯(cuò)誤對象相同。
更多建議: