Child Process

Docs

To create child processes

Spawn

consider following command in bash:
ls -lh /usr
o/p:
total 140K
drwxr-xr-x 1 prasankumar.n 1049089 0 Dec 4 17:07 bin/
drwxr-xr-x 1 prasankumar.n 1049089 0 Dec 4 17:06 etc/
drwxr-xr-x 1 prasankumar.n 1049089 0 Dec 4 17:06 lib/
drwxr-xr-x 1 prasankumar.n 1049089 0 Dec 4 17:06 libexec/
drwxr-xr-x 1 prasankumar.n 1049089 0 Dec 4 17:06 share/
drwxr-xr-x 1 prasankumar.n 1049089 0 Dec 4 17:07 ssl/

Executing same command via spawn syntax

const { spawn } = require('child_process');
const myProcess = spawn('ls', ['-lh', '/usr']); //command, argumentArr, options
myProcess.stdout.on('data', (data) => {
console.log(`stdout: ${data}`);
});
myProcess.on('close', (code) => {
console.log(`child process close all stdio with code ${code}`);
});
myProcess.on('exit', (code, signal) => {
console.log(`child process exited with code ${code}`);
});
myProcess.on('error', (err) => {
console.error('Failed to start child process.'); //Failed to kill ..etc
});
//check setting title for childProcess

Note : The 'close' event is emitted when the stdio streams of a child process have been closed. Multiple processes might share the same stdio streams.

Some useful properties of spawn options are

  • cwd (string): Current working directory of the child process.
  • env (Object) : Environment key-value pairs. Default: process.env.
  • shell (boolean | string) : If true, runs command inside of a shell. Uses '/bin/sh' on Unix, and process.env.ComSpec on Windows. A different shell can be specified as a string. Default: false (no shell).
  • detached (boolean) : docs true makes it possible for the child process to continue running after the parent exits. The child will have its own console window. //For non-windows child process are detached only
  • maxBuffer : specifies the largest number of bytes allowed on stdout or stderr. If this value is exceeded, then the child process is terminated (default small 204 kb ?)

Note : .spawnSync() also exists

  • docs contain example to run piped commands like 'ps ax | grep ssh'

Higher level methods

On top of child_process.spawn() or child_process.spawnSync(), following exists

  • child_process.exec(): spawns a shell and runs a command within that shell, passing the stdout and stderr to a callback function when complete.

  • child_process.execFile(): similar to child_process.exec() except that it spawns the command directly without first spawning a shell by default.

  • child_process.fork(): spawns a new Node.js process and invokes a specified module with an IPC communication channel established that allows sending messages between parent and child.

  • child_process.execSync(): a synchronous version of child_process.exec() that will block the Node.js event loop.

  • child_process.execFileSync(): a synchronous version of child_process.execFile() that will block the Node.js event loop.

Note : In general if command returns more data or it's long running - spawn must be used. As exec has buffer limit which must be increased..etc

Spawning

Spawning .bat and .cmd files on Windows

  • On Unix-type operating systems (Unix, Linux, macOS) child_process.execFile() can be more efficient because it does not spawn a shell by default. On Windows, however, .bat and .cmd files are not executable on their own without a terminal, and therefore cannot be launched using child_process.execFile().

  • Example 1: use child_process.spawn() with the shell option set //better always use spawn style

    const bat = spawn('"my script.bat"', ['a', 'b'], { shell: true });

    Note : If the shell option is enabled, do not pass unsanitized user input to this function. Any input containing shell metacharacters may be used to trigger arbitrary command execution.

  • Example 2 :use .spawn() on cmd.exe

    const bat = spawn('cmd.exe', ['/c', 'my.bat']);
    bat.stdout.on('data', (data) => {
    console.log(data.toString());
    });
    bat.stderr.on('data', (data) => {
    console.error(data.toString());
    });
    bat.on('exit', (code) => {
    console.log(`Child exited with code ${code}`);
    });
  • Example 3: use exec

    exec('my.bat', (err, stdout, stderr) => {
    if (err) {
    console.error(err);
    return;
    }
    console.log(stdout);
    });

Long running process

(Long running process/ unref child process)

  • By default, the parent will wait for the detached child to exit.

    To prevent use the subprocess.unref() method.

    Doing so will cause the parent's event loop to not include the child in its reference count,unless there is an established IPC channel between the child and the parent.

const { spawn } = require('child_process');
const subprocess = spawn(process.argv[0], ['child_program.js'], {
detached: true, /*non-windows, this is default
(read above in useful options section)*/
stdio: 'ignore' /*this to mention child process stdio is not
connected to parent (mandatory if want to unref)*/
});
subprocess.unref(); // parent will not wait for the detached child to exit.

Note : stdio options docs , By default pipes that are established between the parent and child process (stdin, stdout, and stderr)

  • subprocess.ref() : restore the removed reference count for the child process, forcing the parent to wait for the child to exit before exiting itself.

Child process' output into files

const fs = require('fs');
const { spawn } = require('child_process');
const out = fs.openSync('./out.log', 'a');
const err = fs.openSync('./out.log', 'a');
const subprocess = spawn('prg', [], {
detached: true,
stdio: [ 'ignore', out, err ]
});
subprocess.unref();