仕様
~によるとオンラインPOSIX仕様, シェルとユーティリティ, シェルコマンド言語, セクション2.9.3 リストの非同期リストの内容は次のとおりです。
非同期リストの要素(<&>で終わるリスト部分、例:コマンド1、上)シェルによって開始されると、非同期リスト要素の最後のコマンドのプロセスIDは現在のシェル実行環境内で知られている必要があります。シェル実行環境をご覧ください。プロセスIDは、次回まで既知のままにしてください。
コマンドが終了し、アプリケーションはプロセスIDを待ちます。
$!
現在の実行環境では、""(以前の非同期リストに対応)が拡張される前に、別の非同期リストが呼び出されます。実装時に、現在のシェル実行環境の既知のプロセスIDのリストから最新のエントリを{CHILD_MAX}個以上保持する必要はありません。
その他の関連引用:
- 上記のセクション2.12シェル実行環境:
シェル実行環境は、次の部分で構成されます。
[… ]
- このシェル環境で知られている非同期リストの最後のコマンドのプロセスIDについては、非同期リストを参照してください。
- Shell&Utilities、Utilitiesでしばらくお待ちください。
シェルが非同期リスト(非同期リストを参照)を開始すると、非同期リストの各要素の最後のコマンドのプロセスIDは、現在のシェル実行環境内で知られている必要があります。シェル実行環境をご覧ください。
[… ]
スタンバイユーティリティがオペランドなしで呼び出されると、呼び出しシェルに知られているすべてのプロセスIDが終了し、ゼロ終了状態で終了するまで待ちます。
[… ]
既知のプロセスIDは、現在のシェル実行環境の待機呼び出しにのみ適用されます。
何をするのか分からない
Bashでhelp wait
「現在アクティブなすべての子プロセス」を指定します。
仕様では、既知のすべてのプロセスIDのみを指定し、他の非同期リストを呼び出すとプロセスIDが「忘れられる」ようです。
POSIX仕様を正しく解釈すると、次のプログラムは5秒だけ待ちます。
#! /bin/sh
sleep 10 &
sleep 5 &
wait
$!
以前に登場したことがないので、IDを忘れて待っていませんでしたかsleep 5 &
?sleep 10
同様に、2行の間に挿入することも: $!
忘れられませんか?
私のロジックをより明確に説明しましょう。
- 仕様:既知のプロセス。 ID はシェル実行環境の一部です。実装の詳細は重要ではないので、これがいくつかのリストであると想像してみましょう。
- SPEC:
command &
プロセスで結果を実行します。非同期IDはcommand
「既知」(つまり、リストにあります)。- SPEC(疑わしいが最初の引用を参照):
command2 &
何らかの方法で拡張せずに実行すると、$!
procの前のコマンドIDは次のようになります。これ以上不明! (しかし、今proc.IDが知られていますcommand2
。)
- SPEC(疑わしいが最初の引用を参照):
- SPEC:
wait
パラメータなしで既知の手順のみを使用します。身分証明書。 - 結論:したがって、非同期コマンド間で拡張を強制しないと、いくつかのサブプロセスを待つことを忘れる
$!
ことがあります。wait
一部の人々はwait
すべてのプロセスを待っていると思います。仕様は、特定の定義を持つ「既知の」プロセスを表します。一部の人々は、仕様にそのような内容が記載されていなくても、「知られている」が「$!」を意味すると思います(また、「知られているプロセスID」は複数形ではありません$!
)。
私はこれが議論の余地があることに同意します。私が新しい仕事を始めるとき、シェルは私の仕事を忘れません。それでは、仕様をどこで誤って読みましたか?
質問
- POSIXでは、ループで非同期リストを起動するときなど、引数なしで動作を合理的にする
$!
ために実際にforを使用する必要がありますか?wait
- 実際には、このように仕様を実装するシェル(POSIXなど)があります(つまり
: $! expand async. proc. ID to prevent forgetting it
、実際にヌラーを使用するプログラムに追加することを避けることはできますかwait
?
答え1
2つのバックグラウンドジョブを開始するときは、$!
まず最初のジョブのPIDに設定し、次に2番目のジョブのPIDに設定します。これは、シェルが最初の操作を追跡できないという意味ではありません。シェルは実際にあなたがそれを何のために使用しているか気にしません$!
。
標準テキストでwait
引数なしで待機することを伝える方法に注意してください。みんなバックステージ作業?これは、開始されたバックグラウンドジョブの数と、このパラメーターで$!
実行または実行されていない操作とは関係ありません。
示された例では、2つのスリープ呼び出しがバックグラウンドで実行され、両方の呼び出しが終了するのを待ちます。つまり、wait
呼び出しが返されるまでに10秒かかります。