
タイトルの質問を明確にすると、前者がなぜ終了するのかは理解できます。後者が| cat
ループ本体に を追加しただけで終了しない理由は理解できません。
また、おそらく関連していると思われるが、
while true; do echo y; done
私がそうするとすぐに死ぬ^C
が、殺す
while true; do echo y | cat; done
多くの場合、複数回攻撃する必要があります^C
。 1 回で効果が出る場合もあれば、2 回または 3 回で効果が出る場合もありますが、^C
しばらく押し続けて効果がなくなる場合もあります。
両方の動作は bash と zsh の両方で発生しますが、^C
bash ではどちらか一方がよりまれなようです。
どちらの動作でも、これはパイプの追加に限定されませんcat
。| dd
、| tee
などもそれらを引き起こします。echo y | true
ループ本体にパイプが存在すると、それが発生します。
ループ本体にパイプが存在すると、ループの信号に対する応答が変わるのはなぜですか?
答え1
ではwhile true; do echo y; done | true
、が組み込まれているため、ループ内でパイプにecho
書き込むサブシェル プロセスを実行します。y\n
が戻るとtrue
、そのパイプの読み取り側は閉じられるので、書き込み側に書き込むと、SIGPIPE
書き込みプロセスに が配信されます。ここでは、ループを実行しているサブシェル プロセスです。
ではwhile true; do echo y | cat; done | true
、cat
パイプに書き込むのは です。cat
は一般には組み込まれておらず、組み込まれていたとしても、zsh と ksh 以外のシェルでは、すべてのパイプ コンポーネントは常に子プロセスで実行されます。
したがって、ここでは実行中のプロセスのみcat
が終了し、ループを実行するサブシェル プロセスは、stdout に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 はサブシェルでそのコマンドを実行しません)。そのため、サブシェルはtrue
exit にパイプし、kill -l
SIGPIPE によって強制終了されたことを確認します。