采用以下代码:
rm -f pipe
mkfifo pipe
foo () {
echo 1
sleep 1
echo 2
}
#1
exec 3< <(foo &)
cat <&3 # works
#2
foo >pipe &
cat <pipe # works
#3
exec 3<>pipe
foo >&3 &
cat <&3 # hangs
#4 -- update: this is the correct approach for what I want to do
foo >pipe &
exec 3<pipe
rm pipe
cat <&3 # works
为什么方法 #3 会挂起,而其他方法却不会?有没有办法让方法 #3 不挂起?
理由:我希望使用准无名管道来连接多个异步运行的子进程,为此我需要在使文件描述符指向该管道后删除该管道:
mkfifo pipe
exec {fd}<>pipe
rm pipe
# use &$fd only
最佳答案
方法 3 中的问题是 FIFO pipe
然后有 2 个编写器:bash 脚本(因为您已使用 exec 3<>
以读/写方式打开它)和运行 foo
的子 shell 。当所有写入者都关闭文件描述符时,您将读取 EOF。一个编写器(运行 foo
的子 shell)将相当快地退出(大约 1 秒后),从而关闭文件描述符。然而,另一个编写器(主 shell)仅在退出时关闭文件描述符,因为没有关闭文件描述符 3
任何地方。但它无法退出,因为它等待 cat
首先退出。这是一个僵局:
-
cat
正在等待 EOF - EOF仅在主shell关闭fd(或退出)时出现
- 主 shell 正在等待
cat
终止
因此你永远不会退出。
情况 2 有效,因为管道只有一个写入器(运行 foo
的子 shell),该写入器退出得非常快,因此将读取 EOF。在情况 1 中,也只有一位写入者,因为您以只读方式打开 fd 3 ( exec 3<
)。
编辑:删除有关情况 4 不正确的废话(请参阅评论)。这是正确的,因为在读取器连接之前写入器无法退出,因为当读取器尚未打开时打开文件时它也会被阻止。 很遗憾,新添加的情况 4 不正确。它很活泼,只有在 foo
时才有效。在 exec 3<pipe
之前不会终止(或关闭管道)运行。
另请检查 fifo(7)
手册页:
The kernel maintains exactly one pipe object for each FIFO special file that is opened by at least one process. The FIFO must be opened on both ends (reading and writing) before data can be passed. Normally, opening the FIFO blocks until the other end is opened also.
关于Bash重定向: named pipes and EOF,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33159874/