两个窗口,同一用户,带有 bash 提示。在 window-1 类型中:
$ mkfifo f; exec <f
所以 bash 现在正试图从映射到命名管道的文件描述符 0 中读取f
。在 window-2 类型中:
$ echo ls > f
现在 window-1 打印一个 ls 然后 shell 死掉了。为什么?
下一个实验:用 再次打开 window-1 exec <f
。在 window-2 类型中:
$ exec 3>f
$ echo ls >&3
在上面的第一行之后,window-1 被唤醒并打印一个提示。为什么?在上面的第二行之后,window-1 打印ls
输出并且 shell 保持活动状态。为什么?实际上,现在在window-2 中,echo ls > f
并没有关闭window-1 外壳。
答案一定与window-2中引用命名管道的文件描述符3的存在有关?!
它与文件描述符的关闭有关。
在您的第一个示例中,
echo
写入其标准输出流,shell 打开该流以将其与 连接f
,当它终止时,其描述符被关闭(由 shell)。在接收端,从其标准输入流(连接到f
)读取输入的 shell 读取ls
、运行ls
,然后由于其标准输入上的文件结束条件而终止。文件结束条件的发生是因为命名管道的所有写入者(本例中只有一个)都关闭了管道的末端。
在您的第二个示例中,
exec 3>f
打开文件描述符 3 以写入f
,然后echo
写入ls
它。现在打开文件描述符的是shell,而不是echo
命令。描述符保持打开状态,直到您这样做exec 3>&-
。在接收端,从其标准输入流(连接到f
)读取输入的 shellls
运行ls
,然后等待更多输入(因为流仍然打开)。流保持打开状态,因为它的所有写入者(shell、via
exec 3>f
和echo
)都没有关闭它们的管道末端(exec 3>f
仍然有效)。我在上面写过
echo
,好像它是一个外部命令。它很可能是内置在外壳中的。效果还是一样的。没什么:当管道没有写入器时,它看起来对读取器关闭,即在读取时返回 EOF 并在打开时阻塞。
从 Linux 手册页(
pipe(7)
另请参阅fifo(7)
):关闭写端是在结尾隐式发生的
echo ls >f
,正如你所说,在另一种情况下,文件描述符保持打开状态。在阅读了@Kusalananda 和@ikkachu 的两个答案后,我想我明白了。在 window-1 中,shell 正在等待打开管道的写入端然后关闭它的东西。一旦写入端打开,window-1 中的 shell 就会打印一个提示。一旦写入端关闭,shell 就会获得 EOF 并死亡。
在 window-2 方面,我们有我的问题中描述的两种情况:在第一种情况下
echo ls > f
,没有文件描述符 3,所以我们有echo
产卵,它stdin
看起来stdout
像这样:然后
echo
终止,shell 关闭两个描述符。由于文件描述符 1 已关闭并引用f
, 的写入端f
已关闭,这会导致窗口 1 出现 EOF。在第二种情况下,我们
exec 3>f
在我们的 shell 中运行,导致 shell 采用这个环境:现在我们运行
echo ls >& 3
,shell 分配文件描述符echo
如下:然后 shell 关闭上面的三个描述符,包括
f
,但f
仍然有来自 shell 本身的引用。这是重要的区别。正如@Kusalananda 所指出的,关闭描述符 3exec 3>&-
将关闭最后一个打开的引用并导致窗口 1 的 EOF。