複数パターンの終了ステータスを返す「とあるスクリプト」を作成
終了ステータスが成功パターン(exit 0
)、失敗パターンA(exit 1
)、失敗パターンB(exit 2
)のように3パターンにわかれる「とあるスクリプト」を作成しました。(元々のスクリプトはもっと複雑なんですが、ここでは簡略化して書いてます)
処理A || {
# 失敗パターンA
exit 1
}
処理B || {
# 失敗パターンB
exit 2
}
# 成功パターン
exit 0
「とあるスクリプト」の終了ステータスを判定して、それぞれ異なる処理を行うスクリプトを作成
「とあるスクリプト」を「呼び出す側のスクリプト」で、終了ステータスごとに異なる処理を行おうと思い、以下のような条件分岐を書きました。
元々は成功パターンと失敗パターンAの2パターンだけだったんですが、失敗パターンBが登場して3パターンとなり、以下のような分岐にしてみたという経緯があります。
bash とあるスクリプト.sh
if [ $? -eq 0 ] ; then
echo '成功パターンの場合の処理'
elif [ $? -eq 1 ] ; then
echo '失敗パターンAの場合の処理'
elif [ $? -eq 2 ] ; then
echo '失敗パターンBの場合の処理'
fi
想定外の結果に
すると、 exit 1
と exit 2
のどちらの場合も「失敗パターンAの場合の処理
」と出力されてしまいました。
パッと見は間違ってなさそうに見えるんですが、どうにもうまくいきません。なぜでしょう?
問題の原因
「とあるスクリプト」の実行後に if [ $? -eq 0 ] ; then
の部分で [ $? -eq 0 ]
というコマンドが実行されます。
失敗パターンB(exit 2
)の場合は [ 2 -eq 0 ]
なので、判定は偽となり終了ステータスが 1
となります。
$?
は「直前に実行した処理」の終了ステータスが格納される変数なので、 bash とあるスクリプト.sh
を実行した際は $?
に 2
がセットされていますが、 [ $? -eq 0 ]
が実行されることにより $?
が 1
に変わるわけです。
これにより、失敗パターンBの場合、 elif [ $? -eq 1 ] ; then
の部分で [ $? -eq 1 ]
というコマンドは [ 1 -eq 1 ]
になってしまうので、判定は真となり「失敗パターンAの場合の処理
」と出力されていたワケです。
解決方法
この問題を解決するにはどうしたらよいのでしょう?
$?
が上書きされてしまうことが問題なので bash とあるスクリプト.sh
を実行した直後に終了ステータスを変数にセットすることで解決します。
bash とあるスクリプト.sh
result=$?
if [ $result -eq 0 ] ; then
echo '成功パターンの場合の処理'
elif [ $result -eq 1 ] ; then
echo '失敗パターンAの場合の処理'
elif [ $result -eq 2 ] ; then
echo '失敗パターンBの場合の処理'
fi
終了ステータスが2パターンから3パターンに増えて、これからも増えるかもしれないことを考慮すると、 elif
をたくさん並べるよりも case
に書き換えるというのもアリかもしれませんね。
bash とあるスクリプト.sh
result=$?
case $result in
0 )
echo '成功パターンの処理' ;;
1 )
echo '失敗パターンAの処理' ;;
2 )
echo '失敗パターンBの処理' ;;
esac
おまけ
ちょっと前に、「シェルスクリプトの「if」は条件式の「コマンド」の実行結果を判定している」という記事を書いてまして、 if
の仕組みは理解していたつもりだったのにハマってしまいました。。。