Bash 重定向:命名管道和 EOF
Posted
技术标签:
【中文标题】Bash 重定向:命名管道和 EOF【英文标题】:Bash redirection: named pipes and EOF 【发布时间】:2015-10-15 22:55:37 【问题描述】:取以下代码:
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】:方法 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 不正确的废话(参见 cmets)。这是正确的,因为在阅读器连接之前编写器无法退出,因为在阅读器尚未打开时打开文件时它也会被阻止。 不幸的是,新添加的案例 4 不正确。它很活泼,只有当foo
在exec 3<pipe
运行之前没有终止(或关闭管道)时才有效。
同时查看fifo(7)
手册页:
内核为每个由至少一个进程打开的 FIFO 特殊文件维护一个管道对象。 FIFO 必须在两端(读取和写入)都打开,才能传递数据。通常,打开FIFO会阻塞,直到另一端也打开。
【讨论】:
成功了。exec 3<>
使主 shell 成为编写器,这会导致 EOF 问题。
@Irfy 我补充说。在情况 1 中,文件描述符 3 在主 shell 中以只读方式打开。因此,管道永远不会有超过 1 个作者。
在此帮助下,我重写了删除管道的代码,使其按预期工作,谢谢。
@Irfy 不幸的是,#4 也不是真的正确。这实际上是一个竞争条件:如果 foo
在 exec 3<pipe
运行之前退出,exec 3<pipe
将挂起,直到另一个编写器打开 pipe
。
@Irfy 是的,你说得对!编写器 (foo >pipe
) 仅在读取器 (exec 3<pipe
) 连接时开始运行。所以你们都很好。很抱歉造成混乱。以上是关于Bash 重定向:命名管道和 EOF的主要内容,如果未能解决你的问题,请参考以下文章