如何从nodejs正确执行shell脚本

时间:2017-08-23 13:27:15

标签: node.js bash

我需要从nodejs app执行bash脚本。通常我会做这样的事情:

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

但是我最近遇到了一个bash脚本,它在执行时从未终止过。这是一个重现问题的最小例子:

#!/bin/bash
LC_CTYPE=C cat /dev/urandom | tr -dc "a-zA-Z0-9" | fold -w 8 | head -n 1
  • LC_CTYPE=C - 强制tr将所有内容解释为ascii characters
  • tr -dc "a-zA-Z0-9" < /dev/urandom - 读取伪随机字节,丢弃除a-zA-Z0-9
  • 之外的所有内容
  • fold -w 8 - 将输出换行为8个字符的行
  • head -n 1 - 读取第一行(8个字符)

从终端执行时,它可以正常工作,并立即终止:

# ./test.sh 
0J5hsGeh

使用上面的nodejs脚本执行时,它只会挂起:

# node test.js

screenshot from htop command

似乎head -n 1已经终止,但cat /dev/urandom仍在运行。

问题:如何从nodejs执行脚本以使其不挂起?

ENV:

  • 操作系统:Ubuntu 16.04
  • Nodejs版本:v6.11.2

1 个答案:

答案 0 :(得分:0)

这是由NodeJS ignores SIGPIPE signal引起的。当产生子进程时,生成的子进程也会忽略SIGPIPE信号。

因为cat命令在读取第一行后head终止后管道断开时不会终止。因此cat永远从/dev/urandom读取数据。

在NodeJS的未来版本之一中应该是fixed(不确定哪个版本)。目前我只使用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); // <----