There are a couple of ways to execute files and commands, but all use the module child_process
.
child_process.exec
creates a shell and also buffers the whole command’s generated output and sends it to a callback function. So use it only if the output is not too bigchild_process.execFile
runs a file without a shell but IO redirection and file clobbing are not supported. Also on Windows .bat or .cmd files cannot be executed without a shellchild_process.fork
allows you to communicate between parent and child processes by sending messageschild_process.spawn
recommended in most cases as it does not create a shell and works with streams, so it is a better choice when working with large generated command output
Streams in a parent process vs a child process
Unlike in a normal process, in a child process stdout
and stderr
are readable streams and stdin
is writable.
in a parent process | in a child process | |
stdin | …is readable | …is writable |
stdout | …is writable | …is readable |
stderr | …is writable | …is readable |
We can read from readable streams using myStream.on('data', (data) => ...)
.
const { spawn } = require('child_process'); // we define our command that we want to call const child = spawn('cmd', ['/c', 'dir']); child.on('exit', (code, signal) => { console.log(`child process exited with code ${code} and signal ${signal}`); }); /** * Unlike in a normal process, in a child process * stdout and stderr are readable streams and stdin is writable. */ child.stdout.on('data', (data) => { // this will print the directory listing console.log(`Child stdout: ${data}`); }); child.stderr.on('data', (data) => { console.log(`Child stderr: ${data}`); }); child.on('error', (err) => { console.log('Error occurred: ' + err); })
Spawn with options
The following example is almost the same, but this time we inherit the stdio
from the parent. Note, that we do not have to define child.stderr
and so on explicitly:
const { spawn } = require('child_process'); const child = spawn('cmd', ['/c', 'dir'], { shell: true, // we can also use a shell like exec() would do stdio: 'inherit' }); child.on('exit', (code, signal) => { console.log(`child process exited with code ${code} and signal ${signal}`); }); /** * Unlike in a normal process, in a child process * stdout and stderr are readable streams and stdin is writable. */ child.on('data', (data) => { // this will print the directory listing console.log(`Child stdout: ${data}`); }); child.on('data', (data) => { console.log(`Child stderr: ${data}`); }); child.on('error', (err) => { console.log('Error occurred: ' + err); })
Using env variables in processes
We can define our own environment variables (Unix):
const child = spawn('echo $ANSWER', { shell: true, // we can also use a shell like exec() would do stdio: 'inherit', env: { ANSWER: 42} });
Detached mode for background processing
We can run child processes in detached mode, to let them run even if the parent process exited. This is useful for long running background processes:
const {spawn} = require('child_process'); const child = spawn('node', ['timer.js'], { detached: true, stdio: 'ignore' // must be set if detached mode enabled }); // invoking unref() means that the parent process is allowed to exit child.unref();
Parent forks a child process
Allows you to communicate between parent and child processes by sending messages.
Step 1: We create a (child-)script that we will later fork from the parent. It can receive messages from the parent and sends itself messages to the parent. Note that nothing in here says ‘fork’, we only use process
.
process.on('message', (msg) => { console.log('Message from parent: ', msg); }); let counter = 8; setInterval(() => { process.send({counter: counter++}); }, 1000);
Step 2: We create the parent which forks the child script, sends one message to the child and receives messages from the child:
const {fork} = require('child_process'); const forked = fork('child.js'); forked.on('message', (msg) => { console.log('Message from child: ', msg); }); forked.send({hello: 'world'});
Console output will be:
Message from parent: { hello: 'world' } Message from child: { counter: 8 } Message from child: { counter: 9 } Message from child: { counter: 10 } Message from child: { counter: 11 } Message from child: { counter: 12 }