TL; DR
shell スクリプトの場合
# エラーコード 1 を無視
cmd.sh || exit $(($? - 1))
# 複数のエラーコードを無視したい場合 (下記は 1, 2 を無視)
cmd.sh || ( exit $(($? - 1)) ) || ( exit $(($? - 1)) )
Makefile の場合
TARGET:
# エラーコード 1 を無視
cmd.sh || exit $$(($$? - 1))
# 複数のエラーコードを無視したい場合 (下記は 1, 2 を無視)
cmd.sh || ( exit $$(($$? - 1)) ) || ( exit $$(($$? - 1)) )
追記:こちらの方法ではエラーコードを変えるという荒っぽいことをしてますが、エラーコードを変えたくない場合の方法、コメントいただきました。よかったら、そちらもご覧ください。
はじめに
shell スクリプトや Makefile の処理で、「このエラーは処理を続けてほしいんだけど」みたいなこと、たまにありますよね。
sh だと
cmd.sh || true # エラーコードが常に 0 になる
Make だと
TARGET:
# 頭の "-" で、エラーを無視するようになる
-cmd.sh
とかやると、エラーを無視してくれますが、あらゆるエラーが無視されます。そうなると、想定外のエラー発生時にも処理が進んでしまうので、できれば特定のエラー時だけ無視するようにしたいところです。
そこで
# エラーコード 1 を無視
cmd.sh || exit $(($? - 1))
1
のところを別の数値にすれば、好きなエラーコードを指定することができます。
||
は、前のコマンドがエラーコード 1 以上で終わった場合に、後ろのコマンドを実行するようにします。
$?
で直前のコマンドのエラーコードとり、$(( ))
で計算ができるので、1 を引いて、それを新しいエラーコードにしています。
これで、もしエラーコードが 1
なら新しいエラーコードが 0
になって、正常とみなされ処理が継続される、その他のエラーコードならやはり非 0
なので、エラーで停止する、という寸法です。
Makefile でも基本的に同じです。$$
としないと sh のコマンドに $
が渡らないので、そこだけ注意です。
TARGET:
# エラーコード 1 を無視
cmd.sh || exit $$(($$? - 1))
応用編: 複数のエラーコードを無視したい
複数のエラーコードを正常としたいときも、同じものをつなげていけばOK、、、なのですが、このままだと最初の exit で処理が終わってしまうので ( )
とサブシェルにしてあげましょう。(なお、sh スクリプトの場合に、後ろに処理がある場合も ( )
でくくってあげる必要があります)
# 複数のエラーコードを無視したい場合 (下記は 1, 2 を無視)
cmd.sh || ( exit $(($? - 1)) ) || ( exit $(($? - 1)) )
また、2 つめ以降の $?
には、それまでの計算が反映された値が入るので、そこには注意が必要です。上の例の場合、2つめの exit
も -1
してますが、一つ前ですでに 1
引かれているので、最初のエラーコードが 2
の場合に、ここで 0
となります。
cmd.sh || ( exit $(($? - 1)) ) || ( exit $(($? - 2)) )
とすると、エラーコード 1
, 3
を無視することになります。
あとがき
わりとよくあるニーズな気がするのですが、少しググってもページを見つけられなかったので、書いてみました。
「もっとよいやり方があるよ!」という方、ぜひ教えてもらえるとありがたいです