将stdin传递给子进程

时间:2015-07-30 06:40:00

标签: node.js pipe child-process

我使用spawn创建子进程和管道数据:

child process  |  parent process (main)
---------------------------------------
stdout      ----->       process.stdout
stderr      ----->       process.stderr
stdin       <-----        process.stdin

问题在于,当process.stdin管道到子进程stdin时,子进程完成时主进程不会结束。

代码看起来像这样(不是一个非常好的例子,因为ps不使用stdin数据,我想:

var Spawn = require("child_process").spawn;

var ps = Spawn("ps");
process.stdin.pipe(ps.stdin);
ps.stdout.pipe(process.stdout);
ps.stderr.pipe(process.stderr);

如果我删除了process.stdin.pipe(ps.stdin)行,则主要流程结束,但stdin数据不再用管道传输。

ps子进程结束时,为什么主进程没有结束?我该如何解决这个问题?

一个丑陋的解决方案是:

ps.on("close", process.exit.bind(process));

我不喜欢这样,因为我并不想强迫关闭主流程,但我希望自然地关闭 (例如{{1}你等待1000毫秒,然后过程结束)。

1 个答案:

答案 0 :(得分:0)

我不知道这是Node中的错误还是预期的行为,但是有两种解决方法,其中一种可能适合您。

如果应该在子进程死亡时准确地终止当前进程,则可以为exit添加一个处理程序,如下所示:

const fail = err => { throw err }
ps.on("exit", (code, signal) => code !== null ? process.exit(code) : signal !== null ? process.kill(process.pid, signal) : fail("Impossible situation, child process neither exited nor was killed"))

这只会绕过我们的问题,stdin流坐在那里阻止了一切。

如果您确实需要在当前进程中做更多的事情,而不仅仅是运行该子进程,则此方法可能不可接受。相反,您可以做的是destroy process.stdin,恰恰是当您意识到当前流程应该完成的所有工作已经完成时。例如,如果您只想运行ps,则可以添加:

ps.on("exit", (...) => {
  ...
  process.stdin.destroy()
})

,这将具有相同的效果。如果ps失效后您需要做更多的工作,则可以将同一件事放入其他合适的事件处理程序中。