假设我有.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。