Bash シェルスクリプトを安全に実行するための便利な set コマンド
Jenkins で実行するシェルスクリプトを書いていて、
sh ./script.sh
で実行すると実行されるコマンドが Jenkins のコンソールに出力されないから分かりづらいな- コーディングミスとかでエラーになった時は中断してほしいな
- コーディングミスで未定義の変数を使ってたりしたら教えてほしいな
- というか実行前に Lint チェックみたいなことできなのかな
と思ったので調べてみたところ、set
コマンドの各種オプションがそれぞれの要望を叶えてくれることが分かった。
そこで今回は、set
コマンドの便利オプションと使い方を紹介する。
目次
set -x
: シェルスクリプト内のコマンドをコンソール出力するset -v
: 実行するコマンドそのものを出力するset -e
: エラー時にシェルスクリプトを中断するset -u
: 未定義の変数が使用された時にシェルスクリプトを中断するset -n
: コマンドを実行せず構文チェックのみを行うset -o
:set
コマンドでの設定状況を知るset +
: 設定したオプションを無効に戻す- Shebang でセットする書き方がうまくいかなかった
- まとめ
set -x
: シェルスクリプト内のコマンドをコンソール出力する
まず set -x
から。コレをシェルスクリプトの先頭に書いておく。
#!/bin/bash
set -x
echo ほげふが
この状態で $ sh
コマンドを叩くと、以下のように出力される。
$ sh script.sh
+ echo $'?\201??\201\222?\201??\201\214'
ほげふが
日本語部分は数値参照になったりするが、だいたい何のコマンドを叩いたか分かるので助かる。
set -v
: 実行するコマンドそのものを出力する
set -x
に似たオプションが、set -v
。こちらのオプションは、変数などを展開せず出力してくれる。
#!/bin/bash
set -v
MY_VARIABLE='Hoge'
echo $MY_VARIABLE
こんなファイルがあったとして、次のように出力される。
$ sh script.sh
MY_VARIABLE='Hoge'
echo $MY_VARIABLE
Hoge
echo $MY_VARIABLE
部分が分かりやすいだろう。変数展開せず、コマンドをそのまま出力している。
シェルスクリプトの set -v
部分を set -xv
もしくは set -vx
(順不同) とすることで、set -x
オプションとの併用もできる。
$ sh script.sh
MY_VARIABLE='Hoge'
+ MY_VARIABLE=Hoge
echo $MY_VARIABLE
+ echo Hoge
Hoge
+
から始まる行が set -x
によるモノ。set -v
によるコマンド出力なのか、コマンド実行結果の標準出力なのかが一見分かりづらいものの、充分にデバッグできるだろう。
set -e
: エラー時にシェルスクリプトを中断する
お次は set -e
。まずはこのオプションを指定せず、以下のようなシェルスクリプトを用意してみる。
#!/bin/bash
cat none.txt
echo ほげふが
ココで、cat
で出力しようとしている none.txt
というファイルが存在しないとする。通常であれば、以下のような実行結果になる。
$ sh script.sh
cat: none.txt: No such file or directory
ほげふが
cat
コマンドが正常に動かず、その後に書かれた echo
コマンドも実行される。
ココに set -e
コマンドを追加してみよう。
#!/bin/bash
set -e
cat none.txt
echo ほげふが
そしてシェルスクリプトを実行してみると、以下のようになる。
$ sh script.sh
cat: none.txt: No such file or directory
cat
でエラーが出ると、後続の echo
コマンドが実行されていないことが分かる。シェルスクリプトがエラーの時点で中断されているのだ。
もし、エラーが出る場合が想定済みで、エラーを無視したい場合は、次のように || true
とすれば誤魔化せる。
cat none.txt || true
また、-e
オプションを一時的に無効化することもできる。コレについては後述。
set -u
: 未定義の変数が使用された時にシェルスクリプトを中断する
今度は set -u
。コチラは未定義の変数を使用した時にシェルスクリプトを中断してくれる。
#!/bin/bash
echo ほげ
echo $NONE_VARIABLE
echo ふが
例えばこんなコードがあり、$NONE_VARIABLE
という変数が未定義だとする。このままだと、
$ sh script.sh
ほげ
ふが
というように、未定義の $NONE_VARIABLE
を空文字のように扱い、処理が継続してしまう。
コレに対し、
#!/bin/bash
set -u
echo ほげ
echo $NONE_VARIABLE
echo ふが
と set -u
コマンドを設定すると、以下のようになる。
$ sh script.sh
ほげ
script.sh: line 6: NONE_VARIABLE: unbound variable
最後の echo ふが
は実行されておらず、処理がそこで中断されていることが分かる。
set -n
: コマンドを実行せず構文チェックのみを行う
シェルスクリプトの挙動を変更するオプションとしては最後に紹介するモノ。set -n
は、シェルスクリプト内のコマンドは実行せず、構文チェックのみ行ってくれる。
例えば以下のような、if
コマンドの書き方が間違っているスクリプトを用意する。
#!/bin/bash
set -n
echo スタート
if[true]; then
echo HOGE
fi
echo おわり
シェルスクリプトはコマンドの羅列であり、if
・[
・]
はそれぞれ別のコマンドであるから、本来はスペースで区切らないといけないのだが、うっかりスペースを入れずに繋げて書いてしまっている。
コレを実行してみると、
$ sh script.sh
script.sh: line 6: syntax error near unexpected token `then'
script.sh: line 6: `if[true]; then'
と、このように echo
などコマンドは一切実行されず、構文チェックのみ行われている。
コーディング中はこのオプションを付与して構文誤りがないかチェックし、実装が完了したら set -n
コマンドを除去して実際に動作するようにしておこう。
set -o
: set
コマンドでの設定状況を知る
ココからは set
コマンドの活用編。ターミナルで $ set -o
と叩くと、これら set
コマンドのどのオプションが有効・無効になっているか確認できる。こんな感じだ。
$ set -o
allexport off
braceexpand on
emacs on
errexit off
errtrace off
functrace off
hashall on
histexpand on
history on
ignoreeof off
interactive-comments on
keyword off
monitor on
noclobber off
noexec off
noglob off
nolog off
notify off
nounset off
onecmd off
physical off
pipefail off
posix off
privileged off
verbose off
vi off
xtrace off
set +
: 設定したオプションを無効に戻す
ココまで、set -v
・set -e
のように、ハイフン -
でオプションを指定して、そのオプションを有効にしてきたが、これらのオプションを一時的に無効にしたい場合もあるだろう。
その際は、set +v
とか set +o
のように、プラス +
記号でオプションを指定すると、そのオプションを無効化できる。
#!/bin/bash
# エラー時に中断するようにする
set -e
echo ほげほげ
# 以下のコマンドでエラーが起きても、ココだけは無視して継続させたい
# そんな時は set +e でオプションを解除する
set +e
cat none.txt
# また元に戻す
set -e
echo おわり
こんな感じ。
当然だが、set
コマンドはシェルスクリプト内でなくとも、ターミナル上でも使用できるので、先程の set -o
オプションを使って設定状況を見比べてみよう。
# 設定確認
$ set -o | grep xtrace
xtrace off # off の状態
# x オプションを設定する (set -o xtrace と書いても良い)
$ set -x
++ update_terminal_cwd
++ local url_path=
++ local i ch hexch LC_CTYPE=C LC_ALL=
# 省略……
# 設定確認
$ set -o | grep xtrace
+ set -o
+ grep --color xtrace
xtrace on # on になっている
++ update_terminal_cwd
++ local url_path=
++ local i ch hexch LC_CTYPE=C LC_ALL=
# 省略……
# x オプションを切る (set +o xtrace と書いても良い)
$ set +x
+ set +x
$ set -o | grep xtrace
xtrace off # off に戻っている
このように、オプションの On・Off ができている。
Shebang でセットする書き方がうまくいかなかった
この set
コマンドと同等のオプションを、Shebang のところに書いても良いかのように読み取れる文献もあったのだが、自分が試した限りだと上手くいかなかった。
#!/bin/bash -xe
# ↑ こんな風に設定できるらしいが、有効にならず。
仕方がないので、自分は
#!/bin/bash
set -xe
と、Shebang の直後に set
コマンドを書く運用にする。
まとめ
- 実装中に構文チェックしたい (コマンドは実行されない)
set -n
- スクリプト実行時に表示されるコマンドを見たい
set -x
(行頭に+
記号が付き、変数展開される)set -v
(変数展開されない)
- スクリプト実行時にエラーがあったらその時点で中断したい
set -e
(終了コードが0
でないコマンドが出たら中断する)set -u
(未定義の変数が出てきたら中断する)
- 個人的によく使う組み合わせ
set -xeu
以上。set
コマンドでシェルスクリプトがとても安全・便利に書けるようになった。
- 参考 : bashのsetコマンドで覚えておきたい使い方9個 | 俺的備忘録 〜なんかいろいろ〜
- 参考 : シェルスクリプトを書くときはset -euしておく
- 参考 : シェルスクリプトの set -e は罠いっぱい - Togetter
set -e
を使っているとハマるポイント。set -e
オプションによって上手く動かない場合は参考にしたい。