インフラエンジニアたるもの、シェルスクリプトは頻繁に書くと思います。
自由に書きやすい分、メンテナンスがしづらい面も多い言語でもあるので、自分ルールを書き留めておこうと思います。
#シェルの宣言(1行目)には気をつける
1行目にはみなさん何を宣言1しますか?
Linux使いならbashかzshが多いと思う。
UNIX使いなら生粋のsh(bourne shell)が多いと思う(独断)。
ただ、1行目の宣言においては、/bin/sh は環境によってbashだったり他だったりにシンボリックリンクが張られていることが多いので、どんな記述をするか(言語依存の記法)に合わせた宣言をするべき。
特にif文などの条件分岐、比較演算は記法依存が大きいので、そのあたりで使い分けるのがポイント。
自分ルールだと、
- Linuxだと
#!/bin/bash
- UNIX(HP-UX, Solarisなど)だと
#!/bin/sh
としています。
#戻り値は明示的に返す
多くの場合、エラー時には明示的にreturn 1
やexit 1
を返すと思います。
では正常時はどうでしょうか。
これは賛否両論あると思いますが、自分ルールの場合は正常時は exit 0
で明示的に0を返すことにしています。
シェルスクリプトはその性質上、ジョブスケジューラ(個人レベルだとcron、業務レベルだとJP1やHinemosなど)から叩かれることが多いため、ジョブフローの制御において
- 正常終了は0
- 以上終了は1
とされることが多いです。
そのため、正常に終了する場合は明示的に0で返し、異常終了する場合は明示的に1を返すほうが何かと親切な設計になると思います。(いろいろ心配されるんですよ、本当に0で終わるのか?と聞かれたり。。。)
#変数のスコープを意識する
シェルスクリプトは変数のスコープが非常に曖昧です。
別メソッドのスコープ内で宣言した変数は、意図しない限りはいわゆるグローバル変数のように振る舞います。
なので、メソッド内でのみ使うものは意識的にlocal
を付けてローカル変数として扱うほうがよいでしょう。
自分ルールでは以下のようにしています。
- ローカル変数(メソッド内など):
local variable=ほげほげ
- グローバル変数(メインシェル内など):
Variable=ほげほげ
- 環境変数:
export VARIABLE=ほげほげ
#複数本のシェル郡を書く場合は、メインシェルとライブラリの2本立てで作る
シェルスクリプトは非常に読みやすいです。
上から処理順に書いてあるので、読みやすいし、その流れに倣って書きやすいです。
ただし、シェルスクリプト1本で全て完結してよいのは単独な簡易シェルを書く場合のみ。
業務レベルで作成すると何十本という単位でシェルを作成することが多いので、汎用的に使えるようにサブシェルにライブラリ化したうえで、メインシェル側は処理フローのみ記述するようにしましょう。
ライブラリ側を書く時も、できるだけオブジェクト指向に書くほうが汎用性が上がるでしょう。
シェルスクリプトの場合、同名メソッドによるオーバーライドができないのでメソッド名を変えるしか無いですが。。。
たとえばログ関数のような場合、
logging() {
local loglevel=$1
local msgbody=$2
local msg=[${loglevel}]${msgbody}
echo "${msg}"
}
としておいたうえで、ログレベルに応じて呼び出すメソッドを変えてやります。
logging_info() {
logging "INFO" "$1"
}
logging_error() {
logging "ERROR" "$1"
}
エラーレベルの時だけsyslogに出力したくなったら、logging()
を書き変えてあげればよいだけですね。
という感じでライブラリを育ててあげましょう。
ひとまず以上です。
何か書き留めておいたほうが良いことを思い出したら追記します。
-
1行目の宣言のことをシバン/シェバンと呼ぶらしいですね。実はこの記事書いてて初めて知りました。シバン (Unix) - Wikipedia ↩