以下是我想到的一些选项,不确定哪个是正确的。
Sté*_*las 45
当进程尝试写入没有读取器的 SOCK_STREAM 类型的管道(已命名或未命名)或套接字时,它会收到一个 SIGPIPE。
这通常是通缉的行为。一个典型的例子是:
find . | head -n 1
Run Code Online (Sandbox Code Playgroud)
您不想find
在head
终止后继续运行(然后关闭在该管道上打开以供读取的唯一文件描述符)。
该yes
命令通常依赖于该信号来终止。
yes | some-command
Run Code Online (Sandbox Code Playgroud)
将写“y”直到某个命令终止。
请注意,这不仅是在命令退出时,而是在所有读取器都已关闭对管道的读取 fd 时。在:
yes | ( sleep 1; exec <&-; ps -fC yes)
1 2 1 0
Run Code Online (Sandbox Code Playgroud)
将有 1 个(子外壳),然后是 2(子外壳 + 睡眠),然后是 1(子外壳),然后是在子外壳明确关闭其标准输入后从管道读取的 0 fd,这就是什么时候yes
会收到一个 SIGPIPE。
上面,大多数 shell 使用pipe(2)
whileksh93
使用 a socketpair(2)
,但在这方面的行为是相同的。
当进程忽略 SIGPIPE 时,写入系统调用(通常write
,但也可能是pwrite
, send
, splice
...)返回EPIPE
错误。因此,想要手动处理损坏管道的进程通常会忽略 SIGPIPE 并对 EPIPE 错误采取行动。
gol*_*cks 13
(6)
写入失败,因为没有可以从管道读取的进程。
尽管除非您复制描述符和 fork,否则只能从一个进程开始:通常一个管道有一个读取器和一个写入器,当其中一个关闭连接时,管道就失效了。如果您使用命名管道,您可以使用它建立多个连接(串行),但从这个意义上说,每个连接都代表一个新管道。因此,线程或进程的“管道”与文件描述符同义。
来自man 7 pipe
:
如果所有引用管道读取端的文件描述符都已关闭,则 write(2) 将导致为调用进程生成 SIGPIPE 信号。如果调用进程忽略此信号,则 write(2) 失败并显示错误 EPIPE。
所以“断管”对作者来说就像 EOF 对读者一样。
当读取进程在写入进程之前退出时,就会发生管道损坏。所以我会选择(6)