Bash、バックグラウンドプロセスを実行させて他のプロセスを待つ方法は?


11

私は別の持っている(まだ)wait&&&制御フローの質問を..

次のようなスクリプトで、できるだけ多くの作業を同時に実行したいとします。

# may take some hours
something InputA > IrrelevantA &
something InputB > IrrelevantB &

# may take an hour
(
   somethingElse InputA > OutputA &
   somethingElse InputB > OutputB &
)&& combine OutputA OutputB > Result

...morestuff

質問1:スクリプトではcombine、両方のsomethingElseプロセスが完了するまで、両方のプロセスが完了するのを待ちsomethingますか?

質問2:そうでない場合(そうではないと思われる場合)、上記のプロセスがバックグラウンドで動作している間combine、両方のsomethingElseプロセスのみを待機するにはどうすればよいsomethingですか?

回答:


13

あなたの例では、combineコマンドはサブシェルが終了するとすぐに実行されます(最後のバックグラウンドプロセスがエラーなしで開始された場合)。waitコマンドがないため、サブシェルはジョブの開始直後に終了します。

2つ以上の同時バックグラウンドプロセスの戻り値に基づいてコマンドを実行する場合、戻り値に一時ファイルを使用する以外に方法はありません。これは、waitが待機しているプロセスの1つの戻り値しか返せないためです。また、バックグラウンドプロセスは戻り値を取得するためにサブシェルで実行する必要があるため、変数に格納できません。あなたはできる:

something InputA >IrrelevantA &
something InputB >IrrelevantB &

tmp1=$(mktemp)
tmp2=$(mktemp)

( somethingElse InputA >OutputA; echo $? >"$tmp1" ) &
proc1=$!

( somethingElse InputB >OutputB; echo $? >"$tmp2" ) &
proc2=$!

wait "$proc1" "$proc2"

read ret1 <"$tmp1"
read ret2 <"$tmp2"
[ "$ret1" = 0 && "ret2" = 0 ] && combine OutputA OutputB >Result

rm "$tmp1" "$tmp2"

戻り値を本当に気にしない場合は、ジョブを通常どおり開始して、次のように使用できますwait

something InputA >IrrelevantA &
something InputB >IrrelevantB &

somethingElse InputA >OutputA &
proc1=$!

somethingElse InputB >OutputB &
proc2=$!

wait "$proc1" "$proc2"
combine OutputA OutputB >Result

こんにちは、2番目のオプションがうまくいくと思います...
Stephen Henderson

3

特にファイルOutputAとを保存する必要がなくOutputB、気にするだけの場合は、プロセス置換がより効率的になりますResultか?ディスクへの書き込みでI / Oが遅い場合にファイルOutputAを保存するOutputBと、速度が制限されるため、これは特に時間の節約になりますか?

combine  <(somethingElse InputA)  <(somethingElse InputB)  >  Result

プロセス置換を使用すると<(..here..)、出力をファイルに保存してから、「結合」ステップで入力として読み取るのではなく、コマンドを内部に配置できます。

メモリが制限であり、メモリが保持できるサイズ以上のサイズである場合outputAoutputBそれは目的全体を無効にしますか?

ウィルcombineそれが実行を開始する前に、両方のプロセスが完了するまで待つのか?


これは「Jeopardy」ではありません。質問の形式で回答を表現しないでください。真剣に、あなたは新しいアイデアを思いついた、そしてそれはかなり良いと思う。いくつかのポイントに対応するには:combine2つのsomethingElseコマンドが開始するとすぐに実行が開始されますが、<(…)パイプであるため問題ありません。そのためcombinesomethingElseプロセスを超えた場合、データを待つように強制されます。また、パイプであるため、サイズは問題になりません。…(続き)
G-Manは 'Reinstate Monica'

(続き)…私があなたの答えに持っている唯一の実質的な問題は、それがsomethingElseプロセスの終了ステータスをテストすることを許可しないことです-そしてそれが質問者にとって重要であるかどうかは完全に明確ではありません。しかし、また、答えはそのような質問をするべきではありません。
G-Manは 'Reinstate Monica'

2

wait次のコマンドを使用できます。

(echo starting & sleep 10 & wait) && echo done

「開始」の行がすぐに発生し、「完了」が10秒間待機することがわかります。


通常、待機には同じシェルの子プロセスが必要です。待ちはかなりトリッキーです。
mikeserv 2014

1
@mikeserv、何のことを言ってるの?それがポイントです。そのサブシェルのすべての子を待機します。
psusi 14

私の最初のテストではこれはうまくいきます。大きなスクリプトで試してみる
スティーブンヘンダーソン

正確に-同じシェルの子供たち- サブシェル。エスケープしようとしないプロセス、またはデーモン化するプロセスなどで機能します。つまり、プロセスがプロセスリーダーを尊重している限り、大丈夫ですが、プロセスが独自のプロセスリーダーになろうとすると、待機には問題があります。
mikeserv 2014

0

私は実際にこの種のことがどのように行われるかをここの別の答え正確に示しています。その答えは、2つのログがバックグラウンドプロセスによって維持されていることを確認するための質問に対するものだったので、10で実証しました。

デモスクリプト

cat <<-\DEMO >|${s=/tmp/script} 
printf 'tty is %s\nparent pid is %s\npid is pid=%s\n' \
     "$(tty)" "$PPID" "$$"
exec 1>&2 ; nums=$(seq 0 9)
rm ${files=$(printf "/tmp/file%s\n" $nums)}
for n in $nums ; do { for f in $files ; do
    echo "Line $n" >>"$f" ; done
sleep 1 ; } ; done
#END
DEMO

デモを実行

s=/tmp/script ;chmod +x $s ;info="$(($s &)2>&- &)"
echo "$info" ; pid="${info##*=}" ; echo
while ps -p $pid >/dev/null ; do sleep 3 ; done
for f in /tmp/file[0-9] ; do
    printf 'path : %s\tline count : %s\n' \
        $f $(<$f wc -l)
done

出力:

tty is not a tty
parent pid is 1
pid is 12123

path : /tmp/file0    line count : 10
path : /tmp/file1    line count : 10
path : /tmp/file2    line count : 10
path : /tmp/file3    line count : 10
path : /tmp/file4    line count : 10
path : /tmp/file5    line count : 10
path : /tmp/file6    line count : 10
path : /tmp/file7    line count : 10
path : /tmp/file8    line count : 10
path : /tmp/file9    line count : 10

上記は実証します。これは、構築し、名前のスクリプトを実行し/tmp/script chmod「Sの実行としてそれを、そして、それを実行&backgroundします&backgrounded ( subshell )

スクリプトは、rms /tmp/file0-910個のファイルとechoes1秒ごとに10個のファイルすべてへの1行です。$info不名誉なプロセスからいくつかをキャプチャし、キャプチャ$(command substitution). While psした静止レポートを介してそれを提示します。$pidそれはまだ実行中であることがわかっているのでsleep.、完了すると、10個のファイルすべての行が次のようにカウントされます。wc.

この方法でプロセスを呼び出した後、元の親プロセスを自由に閉じることができ、追跡は継続されます-事実上、取り消されます。これはまた、従来のwaitコマンドを使用できないことを意味しますが、ps戻りを待機することは、いずれの場合もより堅牢になるはずです。

言及する価値は、私が思うに、プロセスが実際に最初にで呼び出されていることである$(command substitution)printfs私は$info、私はそれを効果的に制御することができますので、私が欲しいです。しかし、exec 1>&2それが(と同じサブシェルで閉じられる2>&-)でターミナル出力をドロップするとすぐ、プロセスはエスケープし、もう一方の端でそれを待つ必要があります。特に、入力パイプを処理するためにそれを使用する場合、すべてのリダイレクトとプロセスリーダーに心を留めることができる限り、両方の世界の中で最高です。

その他はすべて、ここでのデモ用です。これを実行するために必要なのは、最上位のスクリプトと次のとおりです。

info="$(($script_path &)2>&- &)"    

注:これは、私が実際にデモンストレーションしたいものだけをターミナルに出力します。で述べたように、$PPID,このプロセスは端末によって否認され、その直接の子です$PID 1.

これらの2つを同時に実行して待機する場合はps、両方のPIDを渡して待機します。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.