スクリプトはループ内の子プロセスを待ちません。

スクリプトはループ内の子プロセスを待ちません。

Bashスクリプトは、いくつかのファイルを見つけるためにフォルダを巡回し、ファイルが見つかると、そのファイルを含むディレクトリから関数を呼び出します。下記をご覧ください

pairedread $1 &
pairedread $2 &
pairedread $3 & 
wait
echo "Done ..."

echo 
echo "======================"
echo "Testing again"
echo "======================"
echo

find . -type d -print | while read DIR; do
    echo "reading..."
    test -r "$DIR"/*_1.gz -a -r "$DIR"/*_2.gz || continue
    ( pairedread $DIR &  )
    done

wait
echo "Done..."

pairedreadフォルダをインポートし、指定されたディレクトリのファイルに対してPythonスクリプトを呼び出す関数。最初のケースでは、つまり関心のあるファイルを含むフォルダを明示的に指定すると、スクリプトは実行pairedreadインスタンスを実行し、最終的に終了してから有用なメッセージを表示します。"Done..." 後ろにすべてのサブプロセスが完了しました。

2番目のケースでは、同じ3つのディレクトリを選択し、3つのpairedreadインスタンスを作成します。ただし、スクリプトはまったく待たずに"Done..."すぐに印刷し、サブプロセスがバックグラウンドで実行されている間に返されます。

私は何を逃したことがありませんか?スクリプトを続行する前にサブプロセスが完了するのを待つことができないのはなぜですか?

答え1

(...)パイプと追加のオプションはこれらのプロセスをサブシェルから開始するため、wait待機するサブプロセスがあるかどうかはわかりません。次のサブシェルが必要ないようにループを再構築できます。

while read DIR; do
    echo "reading..."
    test -r "$DIR"/*_1.gz -a -r "$DIR"/*_2.gz || continue
    pairedread $DIR &
done < <(find . -type d -print)

待機は、現在のプロセスの子プロセスについてのみ知っています。これにより、|サイドのstdin / stdoutを一緒に接続するコンポーネントのサブシェルが作成されます。サブシェルで開始されたすべてのプロセスは、「トップレベル」プロセスの子プロセスではないため、waitこれを認識しません。

pairedread()したがって、この場合、構文を使用してサブシェルから明示的に開始し、パイプのループブロック内で発生することによって妨げられます。while

パイプを避け、明示的なサブシェルを削除してそのブロックを再構築し、サブプロセスについてwait外部に通知されたとおりに実行するようにします。

答え2

@Ericが指摘したように、プロセスを待つには、コマンドをサブシェルするのではなく、パイプの外部でバックグラウンドで処理する必要があります。

デュアルフォーク:少なくとも2回フォークすると、そのプロセスは孤立プロセスになり、initプロセスはそのプロセスの親プロセスになります。

コード:3つのフォーク(パイプ、サブシェル、およびバックグラウンド)を実行するため、initプロセスは新しく開始されたプロセスの親プロセスになり、waitは待つだけで待つことはできません。私自身子プロセス

関連情報