bashのset

/ bash

4.3.1.The Set Builtin

https://www.gnu.org/savannah-checkouts/gnu/bash/manual/bash.html#The-Set-Builtin

これを参照してbashスクリプトの冒頭でよく用いられるsetで使えるオプションを気の向くままにまとめる(つまり全部ではない、しかし必要なら上記に全部載っている)。

基本事項

bashのsetはシェルのオプションを設定するビルトインのコマンドとなっている。

インタラクティブシェルに関するオプションと、シェルスクリプトに関するオプションの両方をsetから操作する。前者はふつうにプロンプトで入力することが多く、後者はスクリプトの冒頭にかかれることが多い。

それぞれのオプションはアルファベット一文字からなるコードと、オプション名を表すアルファベット小文字数文字からなる短い名前を持っている。例えば

set -eux

とやるとこれは次と同一

set -o errexit  # エラー時にスクリプトを終了する
set -o nounset  # 未定義の変数を参照したらエラー出して終了する
set -o xtrace   # 実行するコマンドを逐一表示する

もとに戻す場合は-+にすればよい。

set +eux

例によってこれは次と同一

set +o errexit
set +o nounset
set +o xtrace

スクリプト内の変数や関数と同じようにsourceで呼び出している場合を除いて、set -euxなどによる設定はスクリプトが終了するともとに戻るため明示的に戻す必要はない(はず)。

今どのオプションが有効になっているかは特別な変数$-に格納されている。

echo $-

例としてこの結果は以下

himBHs

特に何もせずにこの結果のため、これらのオプションはデフォルトでONになっているということだ。別な方法として以下がある。

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

オプション

コードと短い名前を羅列してく。

allexport / a

変数と関数をすべてexport扱いとする。すなわち、スクリプトが終了しても使用した変数や関数が環境に残る(環境変数)。

notify / b

主にインタラクティブシェル用。バックグラウンドジョブの状態を即座に画面に表示する(通常はユーザの入力を邪魔することが無いように、次のプロンプトが表示される直前に表示されている)。なぜbかは不明。

errexit / e

いくつかの例外を除いて、コマンドが失敗を意味する非ゼロの終了コードを返したときにスクリプトを即座に終了する。

いくつかの例外となるコマンドを以下に示す。

  • while/unitlキーワードに続くコマンド
  • ifキーワードとともに用いられるtestコマンド
  • &&||によって最後以外に実行されるコマンド
  • パイプ|によって最後以外に実行されるコマンド
  • 終了状態が!によって反転されているコマンド

そのほかサブシェルとかに関して細かい挙動が書かれている。いったん省略。

nounset / u

未定義の変数を参照したときに、標準エラー出力に次のような表示をしてスクリプトを終了する(インタラクティブシェルの場合は終了しない)。

./test.sh: 5: a: parameter not set

このオプションが無効なときは未定義の変数を参照しても空の内容に展開されて不都合なければそのままスクリプトが進行する。実際には往々にして不都合の原因となるため、いっそスクリプトを止めてしまうというオプション。

ただし$@$*など特殊なもの除く。$@$*は位置引数$1$2$3、、、をすべてを表す特殊な変数となっている。

xtrace / x

コマンドを実行する直前に、そのコマンドの内容を標準出力に表示する。直前なのでコマンドに含まれる変数などは展開された状態で表示される。

noexec / n

コマンドは読み込むが実際に実行しない。シェルスクリプトの構文が間違っていないかを確認するために用いられる。インタラクティブシェルにおいてこのオプションは無視される。

他人が作ったテスト中のスクリプトでこのオプションが入っていて動かせど動かせど何も起こらないといったミスがありそうなので注意が必要に思う。

noclobber / C

リダイレクトによって既に存在するファイルが上書きされる場合に標準エラー出力に次のようなメッセージを出す。

./test.sh: 5: cannot create test.log: File exists

>>など追記する場合にはエラーは出さない。とにかく今あるファイルを上書きさせたくない場合はシェルスクリプトの冒頭でこのオプションを有効にしておくとよい(test -eなどで判定しなくてよい)。

いったんここまで。

余談

Windowsのcmdにおけるsetは環境変数の参照や設定のためのものだったが、bashのsetはシェルのオプション変更に加えていくつか異なる使い道を持っている。次のように--のあとに引数を渡すとシェル上で定義されている位置引数$1$2、、、を上書きする。

set -- first second third

このときecho $1の結果は

first

となり、そのスクリプトの引数が上書きされていることがわかる。バッチファイルでもこういうことができるのかはわからないが、少なくともbashのsetにはこういう動作がある。

なお、cmdのsetと同じように

set

とすると環境にあるすべての変数/関数を画面に表示できる。cmdの場合と違って関数定義も変数のうちとして扱っているため、関数の中身まで表示されるためその出力行数が単純に多い。