Bash スクリプト内でユーザが任意の意味を付与できるリターンコードの範囲について(あるいは、Ansible の shell モジュールで冪等な処理を一タスクで書くには)
結論を先に書くと、79~125 です。
シェルスクリプトを書いていて、リターンコードによってその後の処理を分けたい場合などに、一体どの範囲のコードを好きに使って良いのかが分からなかったので調べたメモ。
Bash については、右記に記載があります。 ∥ Exit Codes With Special Meanings
たとえば、Bash のコードで言うと下記など。 ∥ shell.h
...
/* Special exit statuses used by the shell, internally and externally. */
#define EX_BINARY_FILE 126
#define EX_NOEXEC 126
#define EX_NOINPUT 126
#define EX_NOTFOUND 127
...
しかしそれとは別に、libc 界隈あたりでエラーをカテゴライズして exit コードを統一しようという動きもあったようで、それは /usr/include/sysexits.h に記載されています。
以上から、こと Bash シェルスクリプトに限って言うと好きに使って良いのは 79~125 となりますが、ひょっとすると “79” はもっと上がってくるかも知れないので、余裕を持って 100 くらいから使っておきましょうかね。
そもそもなぜそんなことが気になったかというと、Ansible の shell モジュールで、冪等な処理を一タスクで書きたかったからです。本当は、状態を確認するタスク、判別するタスク、状態を書き換えるタスクなどに分けるべきなのかも知れませんが、面倒くさいので、一タスクで出来れば良いなと。で、その場合は処理の結果、状態変更が「あった」「なかった」をリターンコードで表したかったので、好きに使えるレンジを調べていたんですね。
結果としては、以下のような感じか。Git の設定が規定のものではなかったら、規定のものに変更する Ansible Playbook タスクです。
- name: Git config (name, email) is set
args:
executable: /bin/bash
shell: |
set -eu
rc=0
if test \
"$(git config --global user.name)" != "{{git_user_name}}" -o \
"$(git config --global user.email)" != "{{git_user_email}}"
then
git config --global user.name "{{git_user_name}}"
git config --global user.email "{{git_user_email}}"
rc=100 # EX__MAX (78) < 100 < EX_NOEXEC (126)
fi
exit $rc
register: ret
failed_when: ret.rc != 0 and not 79 <= ret.rc <= 125
changed_when: ret.rc == 100
要点としては、
- 何をもってエラーとするか(
failed_when
)については Bash 的に、 - 何をもって変更が加わったとするか(
changed_when
)については当該タスク内の取り決めに従って、
判断してやれ、と。この二点がルールを守っていれば良いということですかね。このイディオムで書き進めます。
あ、本件に関してはどちらでも良いのですが、Bourne Shell (/bin/sh) ではなく Bash で実行して欲しい場合には argument に executable
を指定する必要がありますね。