Bashパイプラインで「yes」を使用すると、なぜ無限ループが発生しないのですか?

Bashパイプラインで「yes」を使用すると、なぜ無限ループが発生しないのですか?

文書によると、bashは続行する前にパイプライン内のすべてのコマンドの実行が完了するのを待ちます。

シェルは、値を返す前にパイプライン内のすべてのコマンドが終了するのを待ちます。

それでは、コマンドがyes | trueすぐに完了するのはなぜですか?yes永遠に繰り返され、パイプが絶対に返されないようにする必要はありませんか?


サブ質問もあります。POSIX仕様、シェルパイプラインは、最後のコマンドが完了した後に返すか、すべてのコマンドが完了するのを待つかを選択できます。この意味では、通常のシェルは異なる動作をしますか?yes | true永遠に繰り返されるシェルはありますか?

ベストアンサー1

終了すると、trueパイプの読み取り側は閉じますが、書き込み側への書き込みyes試行は続行されます。この状態を「破損したパイプ」といい、これによりカーネルがSIGPIPE。この信号は特別な処理が行われyesないのでyes終了する。信号を無視すると、writeエラーコードで呼び出しが失敗しますEPIPE。これを行うプログラムは注意を払って書き込みをEPIPE中止する準備ができている必要があります。それ以外の場合は無限ループに陥ります。

strace yes | true1を実行すると、カーネルが2つの可能性に対して独自に準備していることがわかります。

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残念ながら、これはstraceLinux専用です。ほとんどの現代Unixは一部このコマンドは同様の操作を実行しますが、通常は名前が異なり、システムコール引数を完全にデコードできず、時にはルートでのみ機能します。

おすすめ記事