如何使用Unix | 管道(在命令行上)将Node.js脚本连接起来?

61

我知道如何使用Node.js streams将内容串联在一起,但是如果要使用Unix的 | 符号将多个脚本串联在一起,该怎么办?特别是因为其中一些脚本是异步的。

$ ./a.js | ./b.js

示例:

a.js(权限为 0755)

#!/usr/bin/env node

setTimeout(function(){
  console.log(JSON.stringify({ foo: 'bar' }));
}, 10);

b.js (文件权限为 0755)

#!/usr/bin/env node

console.log(process.argv);

这是输出结果:

$ ./a.js | ./b.js
[ 'node', '/Users/viatropos/tests/b.js' ]

events.js:72
        throw er; // Unhandled 'error' event
              ^
Error: write EPIPE
    at errnoException (net.js:883:11)
    at Object.afterWrite (net.js:700:19)

乍一看似乎有很多问题,不确定从哪里开始。有没有办法让这个工作?最终目标是能够获取./a.jsconsole.log输出并在./b.js中使用它。原因是大多数情况下这些脚本将逐个运行,但有时可以将它们组合在一起,因此理想情况下系统应该能够处理这两种情况。


https://dev59.com/RmUp5IYBdhLWcg3wLVKn - Lance
1个回答

81
问题在于你的 b.js 立即结束并关闭了其标准输入,导致 a.js 出现错误,因为其标准输出被关闭而你没有处理这种可能性。你有两个选择:在 a.js 中处理标准输出关闭或在 b.js 中接受输入。
修正 a.js:
process.on("SIGPIPE", process.exit);

如果你加入那一行,当没有人再读取它的输出时,它就会放弃。根据你的程序在做什么,可能有更好的方法来处理SIGPIPE,但关键是停止使用console.log

修复b.js

#!/usr/bin/env node

var stdin = process.openStdin();

var data = "";

stdin.on('data', function(chunk) {
  data += chunk;
});

stdin.on('end', function() {
  console.log("DATA:\n" + data + "\nEND DATA");
});

当然,你不需要对那个数据做任何事情。关键是有一个东西来保持进程运行;如果你将数据传输到它,stdin.on('data', fx) 似乎是一个有用的做法。

记住,这两个方法都可以防止出现错误。如果你计划在程序之间进行传输,则第二种方法可能更有用。


5
非常有帮助。是否有可能以某种方式检查程序是否以“管道”模式(或者我们应该称之为什么)使用?例如,对于CLI程序来说,以下几点将是有用的:a)检查它是否被 forked(if(process.send) {});b)如果没有,检查它是否以“管道模式”调用(就像上面的例子),或者c)如果不是,则正常输出(假设它是独立调用)。这样,CLI程序可以根据使用情况进行自适应。 编辑:我已经找到了答案 (http://nodejs.org/api/tty.html) 。 - Fabdrol

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接