エンジ部ログ

エンジニアもすなるブログというものを、

プログラミング

[waitコマンド] bashで全ての並列処理が終了してからコマンドを実行させたい

はじめに

「bashでプロセスを並列実行させたい!」けれど、「並列実行させたプロセスが全部終わってから次のタスクを実行させたい」という方に向けて本記事を書いていこうと思います。

並列処理だけを実行させる場合

並列処理だけを実行させる場合、例えばbash1.shは以下のようなコードで事足ります。

#!/bin/bash
./a.out &
./b.out &
./c.out &
exit

しかし、これら a.out, b.out, c.out を実行させた後になにかしらの実行をさせたい場合、waitコマンドを使用します。

誤ったコード

以下では、a.out, b.out, c.outを実行後、完了メッセージを表示することを意図しています。

#!/bin/bash
./a.out &
./b.out &
./c.out &
echo 処理a,b,cは終了しました #完了メッセージ
exit

しかし、このコードではa.out, b.out, c.out いずれの終了も待たずに完了メッセージが表示されてしまいます。

正しいコード[waitコマンドを使用]

これらa.out, b.out, c.out の実行終了を待つためにはwaitコマンドを使用する必要があります。以下にwaitコマンドを使用したコードを示します。

#!/bin/bash
./a.out &
./b.out &
./c.out &
wait                 #終了待ち
echo 処理a,b,cは終了しました #完了メッセージ

上記のようにwaitコマンドを挟むことで、a.out, b.out, c.out の実行が終了してから完了メッセージを表示することが出来ました。

waitコマンドとは

waitコマンドとは、プロセスやジョブの終了を待つコマンドです。バックグラウンドで複数のコマンドを実行している時、その全てが終了してから次の処理を行うことが出来ます。

また、多くの場合、waitコマンドでは終了待ちをするプロセスやジョブのプロセスIDをオプションで指定することが出来ます。その形式は以下のように表されます。

wait [pid ...]

さらに、waitコマンドは返り値を持っており、その値によってどのようなステータスでwaitコマンドが実行されたかが分かります。以下の表では返り値とその意味の関係を示しています。

返り値意味
0正常終了
127正常終了
・pidに指定された子プロセスを特定できません。
・実行中の子プロセス以外のプロセスIDをpidに指定しました。
上記以外エラー終了

waitコマンドの注意点

waitコマンドは「内部コマンド・組み込み関数」と呼ばれるものです。シェルコマンドは内部コマンドと外部コマンドの大きく2つに分けられます。詳しい説明は省きますが、外部コマンドはどのシェルにおいても同じ動作をします。他方、内部コマンドはシェルによってその動作が異なる可能性があります。よって、waitコマンドも内部コマンドであるため、シェルによって動作が異なる可能性があります。

実際、bash,dash,zshでは待機中にCtrl+Cを押すと待機をキャンセルしてプロンプトに戻ることができ、csh系ではできないそうです。

waitコマンドの返り値を確認

最後に、waitコマンドの返り値を確認します。返り値はecho $?で見ることが出来ます。

#!/bin/bash
./a.out &
./b.out &
./c.out &
wait
echo $?

./d.out &
./e.out &
wait 4848  #適当なプロセスid 4848
echo $?

以上のようなシェルスクリプトを作成すると、実行結果は

>>0
>>127

となります。これは、最初のwaitでは正常に各プロセスの終了を待つため、0が返り値とされるのに対し、2つ目のwaitコマンドでは適当なプロセスid 4848を指定しているため、指定されたプロセスが見つけられずに終了されたため、返り値が127となりました。

最後に

ここまでいかがだったでしょうか。waitコマンドを使う事でシェルスクリプトにおける並列処理(バックグラウンド実行)の幅は大きく広がると思います。ただし、前述のとおりシェルによって動作が異なる点には注意が必要となるので、慎重に使いましょう。

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

CAPTCHA