5.7 KiB
Child Processes
Node provides a tri-directional popen(3)
facility through the ChildProcess
class.
It is possible to stream data through the child's stdin
, stdout
, and
stderr
in a fully non-blocking way.
To create a child process use require('child_process').spawn()
.
Child processes always have three streams associated with them. child.stdin
,
child.stdout
, and child.stderr
.
ChildProcess
is an EventEmitter
.
Event: 'exit'
function (code, signal) {}
This event is emitted after the child process ends. If the process terminated
normally, code
is the final exit code of the process, otherwise null
. If
the process terminated due to receipt of a signal, signal
is the string name
of the signal, otherwise null
.
See waitpid(2)
.
child.stdin
A Writable Stream
that represents the child process's stdin
.
Closing this stream via end()
often causes the child process to terminate.
child.stdout
A Readable Stream
that represents the child process's stdout
.
child.stderr
A Readable Stream
that represents the child process's stderr
.
child.pid
The PID of the child process.
Example:
var spawn = require('child_process').spawn,
grep = spawn('grep', ['ssh']);
console.log('Spawned child pid: ' + grep.pid);
grep.stdin.end();
child_process.spawn(command, args=[], [options])
Launches a new process with the given command
, with command line arguments in args
.
If omitted, args
defaults to an empty Array.
The third argument is used to specify additional options, which defaults to:
{ cwd: undefined,
env: process.env,
customFds: [-1, -1, -1],
setsid: false
}
cwd
allows you to specify the working directory from which the process is spawned.
Use env
to specify environment variables that will be visible to the new process.
With customFds
it is possible to hook up the new process' [stdin, stdout, stderr] to
existing streams; -1
means that a new stream should be created. setsid
,
if set true, will cause the subprocess to be run in a new session.
Example of running ls -lh /usr
, capturing stdout
, stderr
, and the exit code:
var util = require('util'),
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('exit', function (code) {
console.log('child process exited with code ' + code);
});
Example: A very elaborate way to run 'ps ax | grep ssh'
var util = require('util'),
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('exit', 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('exit', function (code) {
if (code !== 0) {
console.log('grep process exited with code ' + code);
}
});
Example of checking for failed exec:
var spawn = require('child_process').spawn,
child = spawn('bad_command');
child.stderr.setEncoding('utf8');
child.stderr.on('data', function (data) {
if (/^execvp\(\)/.test(data)) {
console.log('Failed to start child process.');
}
});
See also: child_process.exec()
child_process.exec(command, [options], callback)
High-level way to execute a command as a child process, buffer the output, and return it all in a callback.
var util = require('util'),
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);
}
});
The callback gets the arguments (error, stdout, stderr)
. On success, error
will be null
. On error, error
will be an instance of Error
and err.code
will be the exit code of the child process, and err.signal
will be set to the
signal that terminated the process.
There is a second optional argument to specify several options. The default options are
{ encoding: 'utf8',
timeout: 0,
maxBuffer: 200*1024,
killSignal: 'SIGTERM',
cwd: null,
env: null }
If timeout
is greater than 0, then it will kill the child process
if it runs longer than timeout
milliseconds. The child process is killed with
killSignal
(default: 'SIGTERM'
). maxBuffer
specifies the largest
amount of data allowed on stdout or stderr - if this value is exceeded then
the child process is killed.
child.kill(signal='SIGTERM')
Send a signal to the child process. If no argument is given, the process will
be sent 'SIGTERM'
. See signal(7)
for a list of available signals.
var spawn = require('child_process').spawn,
grep = spawn('grep', ['ssh']);
grep.on('exit', function (code, signal) {
console.log('child process terminated due to receipt of signal '+signal);
});
// send SIGHUP to process
grep.kill('SIGHUP');
Note that while the function is called kill
, the signal delivered to the child
process may not actually kill it. kill
really just sends a signal to a process.
See kill(2)