How to run `shell` and more using Node.js

Sometimes an application needs more than Node.js to develop and bootstrap itself. Maybe the project needs some automation from a different programming language than JavaScript; even in that scenario, Node.js can run those required tasks; with that, your whole application could be easier to maintain and won’t have a lot of technologies mixed in the same project.

Subprocesses with Node.js

Running subprocesses with Node.js is relatively simple. Node.js has a built-in module with a mature and stable API dedicated to running child processes, called child_process, yeap.

The exec() method from the child_process module will spawn a shell in your machine, and that’s how you run shell commands using node:

const subProcess = require('child_process')
subProcess.exec('ls', (err, stdout, stderr) => {
  if (err) {
    console.error(err)
    process.exit(1)
  } else {
    console.log(`The stdout Buffer from shell: ${stdout.toString()}`)
    console.log(`The stderr Buffer from shell: ${stderr.toString()}`)
  }
})

You could even write a bit more “complex” shell commands with it; let’s take a closer look:

Img-Complex-Shell-Command

Child Process in Node.js

Child process in Node.js is more potent than simply running shell scripts.

Img-Child-Process

One of my favorite things about this beautiful module is that it is small and powerful, with only four methods. NOTE: These are the async methods, it also includes the sync variants.

img-FourMethods-Async

In the module representation, there are the four methods, the exec() method already covered, the execFile() method, works exactly the same, but it does not spawns a shell by default, instead, it spawns the executable file provided:

const subProcess = require('child_process')
subProcess.execFile('create-react-app awesome-app', (err, stdout, stderr) => {
  if (err) {
    console.error(err)
    process.exit(1)
  } else {
    console.log(`The stdout from create-react-app: ${stdout.toString()}`)
    console.log(`The stderr from create-react-app: ${stderr.toString()}`)
  }
})

NOTE: The exec() and execFile() methods are designed for small output commands; it buffers the output, a memory-heavy operation. Keep that in mind.

On the other hand, the API has the spawn() and fork() methods, let’s cover spawn first:

const subProcess = require('child_process')
const lsChildProcess = subProcess.spawn('ls', [‘-al’])
lsChildProcess.on(‘exit’, () => console.log(‘the ls command finished’’))

The code above is the equivalent of running ls -al in a shell session; the spawn method won’t buffer the output; this could be a little bit more optimal than exec and execFile methods, anyway, the output stills accessible via streams (you can learn more about streams in my Streams blog-post), let’s see:

const subProcess = require('child_process')
const lsChildProcess = subProcess.spawn('ls', [‘-al’])
lsChildProcess.on(‘exit’, () => console.log(‘the ls command finished’’))
// Let’s get the `ls -al` output
lsChildProcess.stdout.on('data', (data) => {
  console.log(`The stdout from create-react-app: ${data)}`)
})

That’s it for spawn().

The only missing part for this APi is the fork() method, the fork() method is simply a special case of spawn(), it was made for spawning Node.js processes, yes, Node.js can run Node.js itself. The API signature is almost the same as spawn() it looks like this:

const subProcess = require('child_process')
const exampleJs = subProcess.fork(‘example.js’)
exampleJs.on(‘exit’, () => console.log(‘the example.js finished’’))
// Let’s get the `node example.js` output
exampleJs.stdout.on('data', (data) => {
  console.log(`The stdout from create-react-app: ${data)}`)
})

The fork() method was designed for running Node.js modules instead of shell or executables like the rest of the API.

And that’s how the child_process API works; if you have any questions or want to have a deeper understanding of the ChildProcess class, please do not hesitate to reach me on Twitter @soyjuanarbol, and do not forget to cc @nodesource as well. We are happy to help.

Refs:

The NodeSource platform offers a high-definition view of the performance, security and behavior of Node.js applications and functions.

Start for Free