请使用以下代码:
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
答案 0 :(得分:2)
方法3中的问题是FIFO pipe
然后有2个编写器:bash脚本(因为你已经使用exec 3<>
打开它读/写)和运行{{的子shell 1}}。当所有编写器关闭文件描述符时,您将读取EOF。一个编写器(运行foo
的子shell)将相当快地退出(大约1秒后),因此关闭文件描述符。然而,另一个编写器(主shell)仅在文件描述符退出时关闭文件描述符,因为文件描述符foo
在任何地方都没有关闭。但它无法退出,因为它等待3
先退出。这是一个僵局:
cat
正在等待EOF cat
终止因此,你永远不会退出。
案例2有效,因为管道只有一个写入器(子shell运行cat
),它很快就会退出,因此将读取EOF。在案例1中,也只有一个作者,因为你打开fd 3只读(foo
)。
编辑:删除有关案例4不正确的废话(请参阅评论)。这是正确的,因为作者无法在阅读器连接之前退出,因为当阅读器尚未打开时,它也会在打开文件时被阻止。 遗憾的是,新添加的案例4不正确。只有当 exec 3<
在foo
运行之前exec 3<pipe
没有终止(或关闭管道)时,它才有效。
另请查看fifo(7)
手册页:
内核为至少一个进程打开的每个FIFO特殊文件保留一个管道对象。在传递数据之前,必须在两端打开FIFO(读取和写入)。通常,打开FIFO块直到另一端打开。