mk-mode BLOG

このブログは自作の自宅サーバに構築した Debian GNU/Linux で運用しています。
PC・サーバ構築等の話題を中心に公開しております。(クローンサイト: GitHub Pages

ブログ開設日2009-01-05
サーバ連続稼働時間
Reading...
Page View 合計
Reading...
今日
Reading...
昨日
Reading...

bash - 複数のバックグラウンド処理の終了判定!

[ サーバ構築 ] [ Linux, Unix, bash, シェル ]

こんばんは。

通常、Linux(Unix 含む) のシェル(bash) で1つのプログラムを流して、正常に終了したか否かはプログラムからのリターンコードで判定します。

しかし、複数のプログラムを同時にバックグラウンドで流した場合は、1つずつ判定することは出来ません。 バックグラウンドで流したプログラムが全て正常終了した時だけ次の処理に進みたい場合に、困ってしまいます。

少し細工が必要です。

当方、意外と使用する局面があるので記録として残しておきます。

作業メモ

0. 前提条件

  • Cygwin 1.7.15 での作業を想定していますが、Linux, BSD でも同様です。
  • 使用するシェルは bash です。
  • bash スクリプト内で実行するプログラムは試験的に Ruby スクリプトにしていますが、何でもかまいません。

1. 実行プログラムの準備

今回のテストでは以下のような Ruby スクリプトを使用する。

0 - 9 の整数乱数を発生させ、その秒数スリープさせる処理を5回繰り返すが、発生した乱数が 0 だったら リターンコード -1(255) を返して終了する。 【ファイル名: test.rb】

1
2
3
4
5
6
7
8
9
10
11
class Test
  5.times do |i|
    r = rand( 10 )
    puts "[#{ARGV[0]}] Sleeping for #{r} seconds."
    if r == 0
      exit -1
    else
      sleep( r )
    end
  end
end

2. bash スクリプトの作成

今回のテストでは以下のような bash スクリプトを使用する。

上記の Ruby スクリプトを3個バックグラウンドで実行し、全て終了したらそれぞれのリターンコードをチェックする。 【ファイル名:test.sh】

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
#!/bin/sh

# プログラムを3個バックグラウンドで実行。
# その際、それぞれの PID を各変数に格納。
ruby test.rb 1 &
pid_1=$!
ruby test.rb 2 &
pid_2=$!
ruby test.rb 3 &
pid_3=$!

# 各プログラムが終了するまで待機し、
# 終了時にそれぞれのリターンコードを取得して変数に格納。
wait $pid_1
ret_code_1=$?
wait $pid_2
ret_code_2=$?
wait $pid_3
ret_code_3=$?

# 各プログラムのリターンコードをチェック
if [ $ret_code_1 -eq 0 ]; then
  echo "[1] [ SUCCESS! ]"
else
  echo "[1] [ FAILURE! ]"
fi
if [ $ret_code_2 -eq 0 ]; then
  echo "[2] [ SUCCESS! ]"
else
  echo "[2] [ FAILURE! ]"
fi
if [ $ret_code_3 -eq 0 ]; then
  echo "[3] [ SUCCESS! ]"
else
  echo "[3] [ FAILURE! ]"
fi

# 全プログラムが正常終了したか否かのチェック
if [ $ret_code_1 -eq 0 -a  $ret_code_2 -eq 0 -a $ret_code_3 -eq 0 ]; then
  echo "[[[ SUCCESS! ]]]"
else
  echo "[[[ FAILURE! ]]]"
fi

3. bash スクリプトの実行

以下のようにして bash スクリプトを実行する。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
$ ./test.sh
[1] Sleeping for 1 seconds.
[2] Sleeping for 0 seconds.
[3] Sleeping for 6 seconds.
[1] Sleeping for 9 seconds.
[3] Sleeping for 6 seconds.
[1] Sleeping for 4 seconds.
[3] Sleeping for 8 seconds.
[1] Sleeping for 7 seconds.
[3] Sleeping for 9 seconds.
[1] Sleeping for 1 seconds.
[3] Sleeping for 4 seconds.
[1] [ SUCCESS! ]
[2] [ FAILURE! ]
[3] [ SUCCESS! ]
[[[ FAILURE! ]]]

これで、バックグラウンドで流した処理が全て正常終了した時だけ次の処理に進むようにする、ということができるようになります。 Windows でバッチプログラムをバリバリ組んでいたこともありましたが、シェルスクリプトの方が断然おもしろいですね。

以上。

Comments