自動化は大切ですが、自動化するときは異常時にちゃんと止まるようにしなければなりません。トヨタ自動車でいうところのニンベンのついた「自働化」である。なぜ自働化が必要かというと、エラー時に止まってくれない機械は稼働中に人が張り付いて見守っていなければならないからです。また、エラーが起こったのちに機械が動き続けるならば、異常なアウトプットが出力され続けることになり、異常なアウトプットを処理しなければならないというムダが発生します。自動化のためのスクリプトを書くときは、エラー時には止まるように作らなければなりません。
しかしながら、シェルスクリプトは恐ろしいことにエラーが起きても既定ではそのまま処理を続けていきます。異常時にちゃんと止まる自働化スクリプトとするためには以下をスクリプトの先頭に書くと良いでしょう。
set -eu -o pipefail trap 'echo "ERROR: line no = $LINENO, exit status = $?" >&2; exit 1' ERR
set -e
set -e echo 1 false echo 2
上記のシェルスクリプトを実行すると、以下のように false のところ、つまり 0 以外で exit したところで止まります。
$ bash sete.sh 1 $ echo $? 1
trap
しかし、上記ではどこで止まったのかが分からないので、どこで止まったのかを trap を用いて表示するようにします。
set -e trap 'echo "ERROR: line no = $LINENO, exit status = $?" >&2; exit 1' ERR echo 1 false echo 2
trap に第1引数で指定されたコマンドがエラー発生に実行されます。 LINENO 変数には現在の行番号が格納されています。実行と以下のようにエラー発生時の行番号と exit status が標準エラー出力に表示されて止まります。
$ bash traperr.sh 1 ERROR: line no = 4, exit status = 1 $ echo $? 1
pipefail
set -e だけだとコマンドをパイプでつないだ場合に上手く止まらない場合があります。
set -e trap 'echo "ERROR: line no = $LINENO, exit status = $?" >&2; exit 1' ERR echo 1 false | true echo 2
を実行すると、 false コマンドが失敗しているはずなのに、止まりません。
$ bash pipefail1.sh 1 2 $ echo $? 0
set -o pipefail をつけるとパイプの途中のコマンドが失敗しても、止まります。
$ cat pipefail2.sh set -e -o pipefail trap 'echo "ERROR: line no = $LINENO, exit status = $?" >&2; exit 1' ERR echo 1 false | true echo 2 $ bash pipefail2.sh 1 ERROR: line no = 4, exit status = 1 $ echo $? 1
set -u
set -u を指定すると宣言してない変数が使用されるとエラーになります。
$ cat setu.sh set -u echo 1 echo $AAA echo 2 $ bash setu.sh 1 setu.sh: line 3: AAA: unbound variable
自働化は運用時の話なので、タイポなんてのは運用前になくなっているはずなので、運用時にはなくてもいいですが、間違っているのに動いちゃっているという状態にならないためにつけておくべきでしょう。