为了澄清标题问题,我理解前者为什么会死。我不明白为什么后者不这样做,只是为了将 a 添加| cat
到循环体中。
也许还有相关的,
while true; do echo y; done
当我这样做时立即死亡^C
,但杀戮
while true; do echo y | cat; done
经常需要击打^C
不止一次。有时一次有效,有时2或3次有效,然后有时我需要坚持^C
一段时间才能死去。
这两种行为都发生在 bash 和 zsh 中,尽管这种^C
行为在 bash 中似乎较少见。
对于这两种行为,这并不限于将管道添加到cat
. | dd
、| tee
等也会导致它们。甚至echo y | true
造成它。循环体中似乎存在任何管道。
为什么循环体中管道的存在会改变循环对信号的响应?
答案1
在 中while true; do echo y; done | true
,由于echo
是内置的,因此您有一个子 shell 进程,它y\n
在循环中写入管道。
返回时true
,该管道的读取端被关闭,因此写入写入端会导致 aSIGPIPE
被传递到写入进程。在这里,这是运行循环的子 shell 进程。
在 中while true; do echo y | cat; done | true
,它cat
写入管道。cat
通常不是内置的,即使是内置的,在 zsh 和 ksh 之外的 shell 中,所有管道组件始终在子进程中运行。
因此,这里只有正在运行的进程cat
会死亡,而运行循环的子 shell 进程会继续运行更多cat
进程,这些进程一旦写入y\n
标准输出就会死亡。
在 ksh93/ksh2020 中,如果您这样做:
$ builtin cat
$ type cat
cat is a shell builtin
$ set -o pipefail
$ while true; do echo y | cat; done | true; kill -l "$?"
PIPE
这次,cat
它是内置的,并且确实在与循环相同的进程中运行(就像cat
第一个管道中最右边的命令一样,ksh 不会在子 shell 中运行该命令),因此子 shell 会通过管道true
退出并kill -l
确认它是被 SIGPIPE 杀死。