为啥 bash 在写入命名管道时关闭?

Posted

技术标签:

【中文标题】为啥 bash 在写入命名管道时关闭?【英文标题】:Why bash is closed while writing to named pipe?为什么 bash 在写入命名管道时关闭? 【发布时间】:2016-06-07 07:44:39 【问题描述】:

在 bash 1 中:

$ mkfifo /tmp/pipe
$ echo 'something' > /tmp/pipe

现在它挂起并等待读取数据。

在 bash 2 中:

$ </tmp/pipe

现在 shell 1 消失了,它关闭了,我的终端消失了。

为什么会这样?

在bash手册中有写

命令替换 $(cat file) 可以替换为 等效但更快 $(

所以我正在试验普通的“

$ bash --version | head -1
GNU bash, version 4.3.11(1)-release (x86_64-pc-linux-gnu)
$ cat /proc/version
Linux version 3.16.0-71-generic (buildd@lgw01-46) (gcc version 4.8.2 (Ubuntu 4.8.2-19ubuntu1) ) #92~14.04.1-Ubuntu SMP Thu May 12 23:31:46 UTC 2016

编辑

在看到最初的 cmets 和答案后,我将添加一些说明。

我不关心不同的命令行语法。

但我真正想要的是在阅读器外壳$ &lt; /tmp/pipe 场景中编写器外壳退出,但在阅读器外壳中使用$ cat /tmp/pipe 时,编写器外壳不会退出。为什么?

我发现我真的没有在问题和正文中表达这个问题,应该可能会提出另一个问题?

【问题讨论】:

$(&lt; file) 是命令替换的特例; &lt; file 不是cat file 的通用替代品。 【参考方案1】:

来自the pipe(7) manual page:

如果引用管道读取端的所有文件描述符都已关闭,则write(2) 将导致为调用进程生成SIGPIPE 信号。

当读取 shell 完成读取并关闭其管道末端时,写入 shell 将收到SIGPIPE 信号,如果它没有捕获到它,那么 shell 将被终止。

【讨论】:

我不认为他们在问这个问题。我想他们在问为什么如果使用&lt; 而不是cat,它不会输出任何东西。 @123 问题标题“为什么 bash 在写入命名管道时关闭?”另有说明。 在这种情况下,这是一个明显的重复,应该标记为一个。 这是正确的。如果你做(echo something &gt; /tmp/pipe); echo $?,你可以看到它。这将打印141,即128+13,而13SIGPIPE。所以 subshel​​l 被 SIGPIPE 杀死了。 为什么 "cat /tmp/pipe" 不会导致 SIGPIPE 写入,而 "/pipe" 会?【参考方案2】:

在手动签名中$variable 连接而不是command prompt

尝试以下脚本:

1)

#!/bin/bash
echo $(< /tmp/pipe);

2)

#!/bin/bash
echo $(cat /tmp/pipe);

两者都能正常工作。

【讨论】:

他没有输入$,他只是将其显示为命令提示符。 是的。我的意思是$$(&lt; file) 中,而不是在$ &lt;/tmp/pipe 这与问题有什么关系,这就是为什么echo something &gt; /tmp/pipe 的进程消失了? 我不知道命令&lt; /tmp/pipe 是什么意思,但请解释一下,在文档中有使用$(&lt; /tmp/pipe) 的示例。总结: cat /tmp/pipe - 在屏幕上打印 something,$(cat /tom/pipe) - 作为命令执行 something,$(something。在我看来&lt; /tmp/pipe 是不正确的命令。【参考方案3】:

当您键入&lt; /tmp/pipe 时,您会将当前shell 的标准输入连接到命名管道。 bash 的工作原理是不断地从其输入中读取并执行它所读取的命令。

    在 shell 1 中,echo something &gt; /tmp/pipe 打开写入管道,写入字符串,然后阻塞,直到有东西读取它。 echo 完成后,它将关闭管道的末端。 &lt; /tmp/pipe 打开管道进行读取,并将其连接到 shell 2 的标准输入。 Shell 2 从管道读取数据(并尝试执行命令)。 回到 shell 1,echo,在从管道读取第二个 shell 后解除阻塞,完成。管道的写入端关闭。 在管道的写入端关闭的情况下,shell 2 在尝试读取另一个命令时会得到一个SIGPIPE,然后退出。

(另一种可能性是,如果 shell 2 从管道读取并尝试执行的命令导致错误,则它会退出。)

另一方面,$(&lt; file) 是命令替换的一种特殊情况。当bash 看到这一点时,它只是从file 本身读取,而不是生成cat 进程并捕获其输出。

【讨论】:

Writer shell (1) 在完成 write() 时获得 SIGPIPE。阅读器外壳 (2) 不退出。

以上是关于为啥 bash 在写入命名管道时关闭?的主要内容,如果未能解决你的问题,请参考以下文章

为啥在没有人阅读后继续写入命名管道?

检测命名管道的关闭

命名管道 232 管道正在关闭

检测阅读器何时关闭命名管道(FIFO)

c中的命名管道

如何写入命名管道而不等待读取管道