我想使用带有mkfifo
的管道来捕获同时运行的几个进程的所有输出,大致类似于下面的
PIPENAME="/tmp/foo"
echo "Make ${PIPENAME:?}" && mkfifo "${PIPENAME:?}"
echo "hello 1" >"${PIPENAME:?}" &
echo "hello 2" >"${PIPENAME:?}" &
wait < <(jobs -p)
cat "${PIPENAME:?}" | sort | uniq
echo "Removing FIFO ${PIPENAME:?}" && rm "${PIPENAME:?}"
然而,上面的挂起并且不起作用,也就是说,echo "hello..." >"${PIPENAME}"
进程都没有终止,因此脚本永远不会到达等待行。
我想,在另一端消耗掉它的输出之前,写入管道的进程不能终止?如果是的话,实现我的目标的标准方法是什么?同样,我希望能够并行启动几个(少于20个(可能长时间运行的命令,并在不丢失任何行的情况下组合它们的输出。
由于FIFO
不是常规文件,而只是对(命名(管道的引用,因此进程只有在两端打开后才能对其进行写入,请参见fifo(7)
。
因此,echo
命令甚至不会开始将其输出写入管道,而是会阻塞,直到另一个进程连接到管道以读取输出。
在这里实现我的目标的规范方法是什么?
很大程度上取决于您的目标是什么:
如果您只想在将多个命令的输出管道传输到另一个命令之前将其组合,请使用pjh答案中的group命令语法。
如果您必须使用FIFO
,请在wait
执行写入命令之前附加读取过程:
echo "hello 1" >"${PIPENAME:?}" &
echo "hello 2" >"${PIPENAME:?}" &
cat "${PIPENAME:?}" | sort | uniq &
wait < <(jobs -p)
如果您只想收集输出以供以后处理,只需使用常规文件即可:
LOGFILE="/tmp/foo"
echo "hello 1" >> "$LOGFILE" &
echo "hello 2" >> "$LOGFILE" &
wait < <(jobs -p)
# anytime later
cat "$LOGFILE" | sort | uniq
但请注意,对于所有这些解决方案,很长的队列或进程的不幸调度可能会导致一个进程的输出被置于另一个进程队列的中间。
为了防止这种情况发生,您可能需要使用适当的日志记录工具。
除非你有其他使用fifo的原因,否则我认为你想要做的事情可以用来完成
{
echo 'hello 1' &
echo 'hello 2' &
wait
} | sort -u