
為了澄清標題問題,我理解前者為什麼會死。我不明白為什麼後者不這樣做,只是為了將 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 殺死。