Bash重定向:命名管道和EOF

时间:2015-10-15 22:55:37

标签: bash named-pipes io-redirection process-substitution

请使用以下代码:

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

1 个答案:

答案 0 :(得分:2)

方法3中的问题是FIFO pipe然后有2个编写器:bash脚本(因为你已经使用exec 3<>打开它读/写)和运行{{的子shell 1}}。当所有编写器关闭文件描述符时,您将读取EOF。一个编写器(运行foo的子shell)将相当快地退出(大约1秒后),因此关闭文件描述符。然而,另一个编写器(主shell)仅在文件描述符退出时关闭文件描述符,因为文件描述符foo在任何地方都没有关闭。但它无法退出,因为它等待3先退出。这是一个僵局:

  • cat正在等待EOF
  • EOF仅在主shell关闭fd(或退出)
  • 时出现
  • 主shell正在等待cat终止

因此,你永远不会退出。

案例2有效,因为管道只有一个写入器(子shell运行cat),它很快就会退出,因此将读取EOF。在案例1中,也只有一个作者,因为你打开fd 3只读(foo)。

编辑:删除有关案例4不正确的废话(请参阅评论)。这是正确的,因为作者无法在阅读器连接之前退出,因为当阅读器尚未打开时,它也会在打开文件时被阻止。 遗憾的是,新添加的案例4不正确。只有当exec 3<foo运行之前exec 3<pipe没有终止(或关闭管道)时,它才有效。

另请查看fifo(7)手册页:

  

内核为至少一个进程打开的每个FIFO特殊文件保留一个管道对象。在传递数据之前,必须在两端打开FIFO(读取和写入)。通常,打开FIFO块直到另一端打开。