bash -eux

https://qiita.com/m-yamashita/items/889c116b92dc0bf4ea7d#bash-%E3%81%AE%E3%82%AA%E3%83%97%E3%82%B7%E3%83%A7%E3%83%B3%E3%82%92%E6%B4%BB%E7%94%A8%E3%81%97%E3%82%88%E3%81%86

 

※ コメントでのご指摘により、こちらの項目は shebang ではなく、 set により明示的にスクリプトの先頭に記述する方式へ修正しました。 @magicant さん、 @syohex さん有難う御座いました!

Bash には便利なオプションが多数用意されています。
それらをスクリプトの先頭に set コマンドにより記述しておく事で、
そのスクリプトを実行中は常にそのオプションが効いた状態で実行されるようにしておけば、
今までいちいち書いていたあんな処理やこんな処理を省略できたり、簡潔に書けたりしますので是非活用しましょう。

僕が普段良く使うのは、 set -eux です。
それぞれの意味について説明します。

-e

普通シェルスクリプトを1度実行すると、途中でエラーがあっても止まってくれず、
何がなんでも最後まで処理を続行しようとしてしまいます。

そんな時、実行時に -e オプションを定義しておくと、そのシェルスクリプト内で 何らかのエラーが発生した時点で、
それ以降の処理を中断する ことができます。

ファイルの作成や消去等、危険なコマンドを肩代わりすることの多いシェルですから、
そういった「取り返しのつかない処理」をやる前に、条件式等で事前チェックを行うと良いですね!

set -e
ls /path/to/file # ls コマンドでファイルが見つからない場合この時点でエラーとなる
cat /path/to/file # 上記でエラーとなった場合この処理が実行される前にスクリプトが中断される。

先ほどの参考演算子の項で説明した通り、条件式はそれ単発で記述すると、
その真偽値によって成功/失敗扱いとなるので、
以下のようにスクリプト内の要所要所に以下のような条件式をおいてあげるだけで、
事前チェック => 偽なら即中止といった処理を実現できます。

set -e

# 〜 中略 〜

[ $hoge -ge $fuga ] 

また、スクリプトの最後を上記のような条件式にすることで、特定の条件を満たしたかどうかで、
そのスクリプト自体の終了ステータスを調整できます。

-u

-u は、未定義の変数に対して読み込み等を行おうとした際に、きちんとエラーとして扱ってくれます。
java でいうところの NullPointerException 的な感じですね!

これを先ほどの : コマンドや -e オプションと組み合わせると、とてもシンプルに引数のチェック等ができます。

set -eu
# 引数が3つ渡されていなければスクリプト実行中止
: $1 $2 $3

たったこれだけで未定義の引数があった場合にエラーで即実行中止してくれます。
スクリプトの先頭付近に何も考えずにとりあえず書いておくだけでも十分効果的です。

もしこれが単純にスクリプト上で $1 $2 $3 を並べただけでは、 $1 がshellのコマンドだと認識されてしまい、
エラーとなってしまうのですが、: の引数として渡すようにすることで、それぞれが上手く数値及び文字列として認識してくれます。
スペースを含む文字列が渡されるような場合は、それぞれの引数を " で囲ってあげることで問題なく処理できると思います。

しかも中止された際のエラーメッセージも、bashが自動的に

./foo.sh: 行 2: $1: 未割り当ての変数です

のようにわかりやすく出力してくれます(上記は日本語の例)。
捗りますね!

-x

最後に -x ですが、これはちょっと他とは方向性が違って、
実行したコマンドを、全て標準エラー出力に出してくれるという代物です。
実行ログと言ったほうがわかりやすいでしょうか?
しかもあくまで標準エラー出力なので、標準出力で何かを期待するようなスクリプトともちゃんと併用ができます!

※ @melpon さんより、標準出力ではなく標準エラー出力との事だったので修正しました。ありがとうございました!

これをつけておくだけでデバッグ時や開発時にかなり役立ちます。

とりわけこのオプションが真価を発揮するのは、JenkinsによるJobを作成している時に、
内部で呼ばれるシェルスクリプト達です。

JenkinsはJobのコンソールログとして -x 相当のものを出してくれますが、
外部スクリプトの中まではそれをしてくれません。
外部スクリプトの実行時に bash -x foo.sh 等としても良いですが、
予めスクリプトの先頭に set -x として書いておくと使う側で意識せずとも常に分かりやすいログになって捗ります。

おまけ: -x 指定時に一緒に出力できる魔法のコメントを書く

-x オプションは便利ですが、もう少し欲を出して、出力されるログをもっと見やすくする為に、
実行時に影響を与えないけど標準出力上に現れる魔法のコメントを書いてみます。

といいつついきなり最初に謝っておきますが、実はこれはコメントじゃないです。 :bow:
ただ実際に処理に影響を与えない為、あたかもコメントかのように利用できるただのコマンドです。

何も影響を与えない…何もしない…

勘の良い方はお気づきかもしれませんが、実はここでまたしても : が出てきます。
以下のように : の引数として文字列を渡してあげることで、
ワンラインでも複数行でも思いのままコメントのようなものが書けます。

: ここにコメントが書ける、コンソールに出力される。

: "特殊な記号等を利用するときはクォーテーションで括る(| や & 等)"

: "
こうすれば
複数コメントも書ける。
ちゃんと改行もされて出力される。
"

: コマンドは引数として文字列を受け取りますが、実際受け取った引数をどうするわけでもなく、
無条件にステータスコード0で終了するので、実際には何も処理されていません。
ですが通常のコマンドとは違ってちゃんと一つのコマンドとして成立しているので、
-x オプションの出力結果にはしっかり出力されるというわけですね!

一時的にオプションの効果を無効化したい

set によるオプションは便利ですが、これらをスクリプト中で一時的に無効化したい事がよくあります。
そんな時は、 set +x や set +eu 等のように、 - ではなく + を指定してあげると良いです。
無効化したい処理が終わったら、また忘れずに set -eu 等とすれば、そこから元通りになります。

set -eux

# 中略

set +u # 一時的に -u オプションを無効化。

foo=$1 # この $1 は未定義かもしれないが、未定義でもエラーとならない。
echo $foo

set -u # -u オプションを元通り付与し直す。

# 以降の処理
posted on 2018-06-08 16:09  guolongnv  阅读(1546)  评论(0)    收藏  举报