有些程序可以有无限的运行时间并产生无限的输出。当在带有完成命令的管道中使用时,管道如何知道何时停止?
例如,采用yes
(无限输出)head
:
yes | head -n 5
它只会产生 5 y
。
结束的第一个命令是停止其他进程输入/输出的命令吗?
它是如何运作的?
答案1
这些命令通过管道连接(我在这里谈论的是系统原语 - 显然,它们通过 a 连接|
)。当管道的读取端 ( stdin
of head
) 变为close
d (== 当head
显式 ( close
) 或隐式(退出)关闭它时),尝试写入写入端 ( stdout
of yes
) 将失败。
默认情况下,这不仅仅是常规errno
故障,而是导致写入进程接收信号的故障SIGPIPE
。默认处理程序操作SIGPIPE信号是终止。
简而言之,如果您写入损坏的管道,系统将向您发送 a SIGPIPE
,并且默认情况下,aSIGPIPE
会杀死您。这就是为什么在结束yes
时终止head
(从而破坏管道)。
如果您在父 shell 中忽略SIGPIPE
,则命令将继承此配置,并且write
对损坏的管道的 a 只会errno
导致EPIPE
.如图所示,yes
将此错误字符串化并打印它:
$ (trap "" SIGPIPE; yes | head -n 5)
y
y
y
y
yes: standard output: Broken pipe
yes: write error