例えば以下のようなスクリプトがあって、その結果を bash 内で実行し標準出力を環境変数として export したい。しかも、そのスクリプトは失敗する可能性があると仮定する(インターネット接続が必要なのに繋がってない環境で実行された。設定ミスによって権限が足りてない。単純なバグ...など)。
これがビルドやデプロイのために実行されるコードだった場合(例えば Docker の entrypoint )、実行に失敗した瞬間に安全のため処理を中断させたい。必要な環境変数を設定し損ねたアプリケーションは正常に動くとは全く期待できないし、想定してない動作をする恐れもあるため。
import sys # 検証のため何か引数が渡された場合、エラーにする raise_error = bool(len(sys.argv) >= 2 and sys.argv[1]) if raise_error: raise Exception("Cannot get the token.") print("secret-token-string")
中断させる書き方
set -e
と書くことで、実行したコマンドでエラーが出た時に中断させることができる。
export は一行で export SECRET_TOKEN="$(python ./get_token.py)"
と書くこともできるが、このように書いてしまうと python ./get_token.py
が失敗しても「export コマンド」は成功する。よって最終的なコマンドの実行ステータスは 0 となり中断されない。
export コマンドを分けることによって、ちゃんとコマンドの失敗時に処理が中断されるようになる。
#!/bin/bash set -e SECRET_TOKEN="$(python ./get_token.py error)" export SECRET_TOKEN echo "\$SECRET_TOKEN = '$SECRET_TOKEN'"
Traceback (most recent call last): File "./get_token.py", line 6, in <module> raise Exception("Cannot get the token.") Exception: Cannot get the token.
export を一行で書いた場合
一番最後の echo コマンドが実行された。環境変数に空文字が設定された状態になってしまった。
#!/bin/bash set -e export SECRET_TOKEN="$(python ./get_token.py error)" echo "\$SECRET_TOKEN = '$SECRET_TOKEN'"
Traceback (most recent call last): File "./get_token.py", line 6, in <module> raise Exception("Cannot get the token.") Exception: Cannot get the token. $SECRET_TOKEN = ''
ShellCheck でまずい書き方を教えてもらう
export の書き方は ShellCheck の wiki で知ることができた。
ShellCheck: SC2155 – Declare and assign separately to avoid masking return values.
ShellCheck は shell script 用の静的な解析ツール(linter)で、VS Code の extension として使えたり、CI に組み込むことができる(公式の docker image があるので CI 化は楽にできた)。
個人的に、shell script に関してはわからないことだらけなので積極的に使っていきたい。