Reputation: 885
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
LC_CTYPE=C
- force the tr
to interpret everything as ascii characterstr -dc "a-zA-Z0-9" < /dev/urandom
- read pseudorandom bytes, discard everything except a-zA-Z0-9
fold -w 8
- wrap output into lines 8 characters longhead -n 1
- read the first line (8 characters)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
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:
Ubuntu 16.04
v6.11.2
Upvotes: 1
Views: 686
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