文書によると、bashは続行する前にパイプライン内のすべてのコマンドの実行が完了するのを待ちます。
シェルは、値を返す前にパイプライン内のすべてのコマンドが終了するのを待ちます。
それでは、コマンドがyes | true
すぐに完了するのはなぜですか?yes
永遠に繰り返され、パイプが絶対に返されないようにする必要はありませんか?
サブ質問もあります。POSIX仕様、シェルパイプラインは、最後のコマンドが完了した後に返すか、すべてのコマンドが完了するのを待つかを選択できます。この意味では、通常のシェルは異なる動作をしますか?yes | true
永遠に繰り返されるシェルはありますか?
答え1
終了すると、true
パイプの読み取り側は閉じますが、書き込み側への書き込みyes
試行は続行されます。この状態を「破損したパイプ」といい、これによりカーネルがSIGPIPE
。この信号は特別な処理が行われyes
ないのでyes
終了する。信号を無視すると、write
エラーコードで呼び出しが失敗しますEPIPE
。これを行うプログラムは注意を払って書き込みをEPIPE
中止する準備ができている必要があります。それ以外の場合は無限ループに陥ります。
strace yes | true
1を実行すると、カーネルが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残念ながら、これはstrace
Linux専用です。ほとんどの現代Unixは一部このコマンドは同様の操作を実行しますが、通常は名前が異なり、システムコール引数を完全にデコードできず、時にはルートでのみ機能します。
答え2
yes | trueが永遠に繰り返されるシェルはありますか?
yes
コマンドがパイプを使用しているため、パイプが破損してもコマンドが失敗する可能性はほとんどありません。sleep
一方、パイプは使用されないため、次のようになります。
sleep 100000000 | true
少なくとも100000000秒間実行されます。