命名管道、文件描述符和 EOF

Fix*_*xee 10 file-descriptors fifo

两个窗口,同一用户,带有 bash 提示。在 window-1 中输入:

$ mkfifo f; exec <f
Run Code Online (Sandbox Code Playgroud)

所以 bash 现在试图从映射到命名管道的文件描述符 0 中读取f。在窗口 2 中键入:

$ echo ls > f
Run Code Online (Sandbox Code Playgroud)

现在 window-1 打印一个 ls 然后 shell 死了。为什么?

下一个实验:再次打开 window-1 exec <f。在窗口 2 中键入:

$ exec 3>f
$ echo ls >&3
Run Code Online (Sandbox Code Playgroud)

在上面的第一行之后,window-1 唤醒并打印提示。为什么?在上面的第二行之后,window-1 打印ls输出并且 shell 保持活动状态。为什么?事实上,现在在window-2中,echo ls > f并没有关闭window-1外壳。

答案一定与window-2 中引用命名管道的文件描述符 3的存在有关?!

Kus*_*nda 12

它与文件描述符的关闭有关。

在您的第一个示例中,echo写入外壳打开以将其连接到的标准输出流f,并且当它终止时,其描述符被关闭(由外壳)。在接收端,从其标准输入流(连接到f)读取输入的 shell读取ls、运行ls,然后由于其标准输入上的文件结束条件而终止。

出现文件结束情况是因为命名管道的所有写入者(在本例中只有一个)都关闭了它们的管道末端。

在您的第二个示例中,exec 3>f打开文件描述符 3 以写入f,然后echo写入ls它。现在打开文件描述符的是 shell,而不是echo命令。描述符保持打开状态,直到您执行exec 3>&-。在接收端,从其标准输入流(连接到f)读取输入的 shell读取ls、运行ls然后等待更多输入(因为流仍处于打开状态)。

流保持打开状态,因为它的所有写入者(外壳、viaexec 3>fecho)还没有关闭管道的末端(exec 3>f仍然有效)。


我在echo上面写过,好像它是一个外部命令。它很可能内置于外壳中。不过效果是一样的。


ilk*_*chu 6

没什么可说的:当管道没有写入者时,它看起来对读者关闭,即读取时返回 EOF,打开时返回阻塞。

从 Linux 手册页(pipe(7),但另请参阅fifo(7)):

如果所有引用管道写端的文件描述符都已关闭,则尝试read(2)从管道中将看到文件结尾(read(2)将返回 0)。

关闭写入结束是在 结束时隐式发生的事情echo ls >f,正如您所说,在另一种情况下,文件描述符保持打开状态。