使用管道了解 subshel​​l 和 stdout 的行为

使用管道了解 subshel​​l 和 stdout 的行为

假设我有.c文件和相应的可执行文件(假设为 foo),它从 stdin 接收一些输入,然后对/bin/sh.向该可执行文件提供输入,如下所示:

python -c "<some script to feed input>" | ./foo

我观察到 foo 调用的 shell 立即关闭并且 foo 终止。然而,IRC 上有人建议像这样执行:

(python -c "<some script to feed input>"; cat) | ./foo

保持调用的子 shell./foo仍在运行。我想知道这里发生了什么事。

我的推测:对于第一种情况,python 脚本的标准输出是否在完成后立即关闭,从而将 EOF 发送到./foo终止进程的标准输入./foo?但这对我来说没有意义,因为系统调用应该是一个阻塞调用,导致./foo不终止。我希望得到帮助和指向资源的指针来纠正错误的理解。谢谢!

答案1

不存在“发送 EOF”这样的事情。当没有更多数据可供读取时,即到达文件结尾。

在第一个片段中,一旦 Python 脚本退出,就不再有进程打开管道进行写入。因此,一旦foo读取完管道上发送的所有数据,它就会在其标准输入上检测到文件结束条件。

在第二个片段中,一旦 Python 脚本退出,管道仍然由子 shell 打开。因此,即使foo读取完Python脚本产生的所有数据,它也会继续等待更多的输入。子 shell 启动cat,它从它自己的标准输入读取和转发数据。一旦cat退出,情况与以前相同:不再有进程打开管道进行写入并且foo将到达其输入的末尾。

当进程在read系统调用中被阻止时,系统调用可能返回的原因有多种:

  • 如果数据可用,read则返回正值并将那么多字节存储在传递给它的缓冲区中。
  • 如果已到达文件末尾,read则返回 0。对于常规文件,当文件位置到达文件末尾时会发生这种情况。对于管道,当最后一个打开文件的进程终止并且管道的缓冲区已完全消耗时,就会发生这种情况。
  • 如果发生错误,则read返回-1。

相关内容