ドキュメントによると、bashはパイプライン内のすべてのコマンドの実行が完了するまで待機してから続行します
シェルは、パイプライン内のすべてのコマンドが終了するのを待ってから、値を返します。
では、なぜコマンドyes | true
すぐに終了しますか?yes
が永久にループし、パイプラインが戻らないようにする必要はありませんか?
そして、サブ質問: POSIX仕様 によると、シェルパイプラインは、最後のコマンドが完了した後に戻るか、すべてのコマンドが完了するまで待機するかを選択できます。一般的なシェルはこの意味で異なる動作をしますか? yes | true
は永久にループしますか?
true
が終了すると、パイプの読み取り側は閉じられますが、yes
は書き込み側への書き込みを続行します。この状態は「壊れたパイプ」と呼ばれ、カーネルがSIGPIPE
信号をyes
に送信します。 yes
はこのシグナルについて特別なことは何もしないため、強制終了されます。シグナルを無視した場合、そのwrite
呼び出しはエラーコードEPIPE
で失敗します。これを行うプログラムは、EPIPE
に気づいて書き込みを停止する準備をする必要があります。そうしないと、無限ループに入ります。
もし、するなら strace yes | true
1 両方の可能性に備えてカーネルが準備していることがわかります。
write(1, "y\ny\ny\ny\ny\ny\ny\ny\ny\ny\ny\ny\n"..., 4096) = -1 EPIPE (Broken pipe)
--- SIGPIPE {si_signo=SIGPIPE, si_code=SI_USER, si_pid=17556, si_uid=1000} ---
+++ killed by SIGPIPE +++
strace
は、デバッガーAPIを介してイベントを監視しています。デバッガーAPIは、最初にエラーを返すシステムコールについて通知し、次にシグナルについて通知します。ただし、yes
の観点から見ると、シグナルが最初に発生します。 (技術的には、シグナルはカーネルがユーザースペースに制御を返した後、マシン命令が実行される前に配信されるため、Cライブラリのwrite
"ラッパー"関数はerrno
を設定してアプリケーションに戻る機会がありません。 )
1 悲しいことに、strace
はLinux固有です。最近のほとんどのUnixには、似たようなsomeコマンドがありますが、名前が異なる場合が多く、syscall引数が完全にデコードされず、ルートでのみ機能する場合があります。
あるシェルはありますか? trueは永久にループしますか?
おそらく、yes
コマンドはパイプを使用しているため、パイプが壊れると失敗します。一方、sleep
はパイプを使用しないため、次のようになります。
sleep 100000000 | true
少なくとも100000000秒間実行されます。