Prvaak
Prvaak

Reputation: 885

How to properly execute shell script from nodejs

I need to execute a bash script from nodejs app. Usually I would do something like this:

var childProcess = require('child_process');
childProcess.execFile('./test.sh', function (error, stdout, stderr) {
  console.log(error, stdout, stderr);
})

But I recently ran into a bash script that never terminated when it was executed like that. This is a minimal example that reproduces the issue:

#!/bin/bash
LC_CTYPE=C cat /dev/urandom | tr -dc "a-zA-Z0-9" | fold -w 8 | head -n 1

When executed from terminal it works fine and it terminates immediately:

# ./test.sh 
0J5hsGeh

When executed using the above nodejs script it just hangs:

# node test.js

screenshot from htop command

It seems that the head -n 1 already terminated but the cat /dev/urandom is still running.

Question: How to execute the script from nodejs so that it does not hang?

Env:

Upvotes: 1

Views: 686

Answers (1)

Prvaak
Prvaak

Reputation: 885

This is caused by the fact that NodeJS ignores SIGPIPE signal. When a subprocess is spawned the SIGPIPE signal is ignored by the spawned subprocess as well.

Because of that the cat command does not terminate when the pipe is broken after the head terminated after reading the first line. So the cat reads data from /dev/urandom forever.

It should be fixed in one of the future versions of NodeJS (not sure which though). For now I just use the workaround from that issue.

var childProcess = require('child_process');
process.on('SIGPIPE', noop); // <----
childProcess.execFile('./test.sh', function (error, stdout, stderr) {
  console.log(error, stdout, stderr);
})
process.removeListener('SIGPIPE', noop); // <----

Upvotes: 2

Related Questions