Bash重定向: named pipes and EOF

标签 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

最佳答案

方法 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/

相关文章:

c++ - 创建不带 PIPE_REJECT_REMOTE_CLIENTS 的NamedPipe

perl - 如何通过 Perl 以编程方式控制交互式 Unix 应用程序?

bash - 在将 stdout 和 stderr 写入日志文件时是否可以仅将 stdout 打印到屏幕?

bash - Bash脚本通过SSH远程传递命令

PuTTY 中用于 session 管理的 Linux Screen

windows - 命名管道 Matlab

linux - Bash - 如何使用 printf 打印多行字符串(带有 '\n' )

bash - 捕获任何 STDERR 数据的函数

python - 根据查找批量重命名文件

使用脚本进行 MySQL 身份验证,无需以纯文本形式提供密码