シェルスクリプトを書いていたところで、set -eやtrapの挙動に引っかかってしまいました。
なお、「特定の環境で動けばいい」という前提なので、シバンの段階で#!/bin/bashと決め打っています。POSIXへの準拠性などは考えません。
関数化したら、意図しない動作に
似たような動作をするシェルスクリプトがあったので、一部を関数にして切り出すことにしました。set -eとtrap ERRの組み合わせで、エラー時の終了処理はもともと組んでありました。
# main.sh
source ./functions.sh
failure() {
echo エラー発生!
}
trap failure ERR
set -e
func
echo 正常終了
# functions.sh
func() {
# 処理失敗のシミュレーション
false
echo 'func complete'
}
さて、上のコードを実行すれば、何を表示するでしょうか。意図としては、「エラー発生!」だけになってほしいのです…が、なんと何も表示せず終了してしまいます。
動作確認と狙い通りな形への改造
何が起きたのかと調べてみると、以下のような動作をしていたのでした(manより)。
-
set -e…関数内まで適用される -
trap ERR…関数内にはデフォルトでは適用されない
ということで、関数内のエラーではtrapに入らず即座に終了してしまう、という挙動となっていました。
そして、set -Eとすればtrap ERRが関数にも適用される、ということでやってみたら、今度はエラーが2回表示されるようになりました。今回の場合、一度trap ERRに入れば復帰する目がなかったので、そのままtrapの関数の中でexitさせることで、2回目が来る前に終了させて解決しました。
set -E
failure() {
echo エラー発生!
exit 1
}
教訓
いざという時、manは役に立つ