bashスクリプトはすべてのスリープコマンドを実行しません

bashスクリプトはすべてのスリープコマンドを実行しません

以下のコードはLinuxシステムで実行されている単純なbashスクリプトで、各出力間の時間間隔が次の理由を知りたいと思います。4つ 第二変える

$ for test in test1 test2 test3; do (echo ${test}; sleep 4s; echo hop2; sleep 4s; echo hop3) | date;  done
Sun 11 Apr 2021 12:42:27 AM +07
Sun 11 Apr 2021 12:42:31 AM +07
Sun 11 Apr 2021 12:42:35 AM +07

後者の時間値を少し増やしても、各出力間の時間はまだ4秒です。

$ for test in test1 test2 test3; do (echo ${test}; sleep 4s; echo hop2; sleep 50s; echo hop3) | date;  done
Sun 11 Apr 2021 12:42:44 AM +07
Sun 11 Apr 2021 12:42:48 AM +07
Sun 11 Apr 2021 12:42:52 AM +07

これはとても混乱していますが、誰もがこれを説明できればとても感謝します。

より混乱するのは、コマンドを前に置くとdateスリープコマンドが実行されないように見えることです。

$ for test in test1 test2 test3; do (date; echo ${test}; sleep 50s; echo hop2; sleep 50s; echo hop3) | date;  done
Sun 11 Apr 2021 01:22:35 AM +07
Sun 11 Apr 2021 01:22:35 AM +07
Sun 11 Apr 2021 01:22:35 AM +07

ベストアンサー1

これを明確にするために「hop2」をエコーする前と後(パイプバイパス)stderrにデバッグ出力を追加します。

$ for test in test1 test2 test3; do 
      (echo ${test}; sleep 4s; echo before hop2 >&2;
       echo hop2; echo after hop2 >&2; sleep 4s; echo hop3) | date;
  done
Sat Apr 10 11:29:46 PDT 2021
before hop2
Sat Apr 10 11:29:50 PDT 2021
before hop2
Sat Apr 10 11:29:54 PDT 2021
before hop2

気づくecho after hop2 >&2 絶対に実行しないでください、そしてそれに続くコマンド:2番目sleepecho hop3

私が理解したのは、これが起こったことです。ループ内では、2つの別々のプロセスが並列に実行され、最初のプロセスの出力が2番目のプロセスの入力に接続されます。 2つのプロセスが実行されます。

echo ${test}
sleep 4s
echo before hop2 >&2
echo hop2
echo after hop2 >&2
sleep 4s
echo hop3

そして

date

おおよその実行順序は次のとおりです(最初のステップ3の正確な順序とステップ4の開始はややランダムです)。

  1. プロセス1が実行されますecho ${test}。これは、「test1」(および改行文字)をパイプに書き込んで後で読み取れるようにバッファリングされます。
  2. プロセス2を実行しdate、現在の日付を端末に印刷します。
  3. プロセス2が終了し、パイプの端が閉じられる。
  4. プロセス1が実行されますsleep 4s
  5. 4秒後、プロセス1が実行され、echo before hop2 >&2「before hop2」が端末に印刷されます。
  6. プロセス1努力する実行がecho hop2パイプの唯一のリーダーがパイプを閉じたため、SIGPIPE エラーが発生します。これにより、明らかに完全なサブシェルプロセス(echoコマンドだけでなく)が終了します。

これはechoシェルが組み込まれているために発生します。/bin/echo hop2(シェルの組み込みechoコマンドではなく外部コマンド)を使用すると、sleep期待どおりに2番目のコマンドが実行されます。

ちなみに、これは他のシェルで比較的一貫しています。 bash、zsh、dash、ksh(対話型)で同じ結果を得ました。スクリプトのkshは、続行する前にプロセス1が終了するのを待たないという点で若干異なります。したがって、すべてのdatesがすぐに実行され、その後に一連の「hop2の前」行(4秒後)が続きます。

おすすめ記事