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