未定義変数の判定
混乱が見受けられるので、きっちり定義をしておく。ただし、ここでの用語であって、汎用性はない。
変数が定義されていない場合、「未定義変数」と表記。
code:unset_var
unset UVAR
変数が定義されているが空文字列の場合、「空変数」と表記。
code:empty_var
EVAR=
変数が定義されていて空文字列ではない場合、「有効値変数」と表記。
code:valid_var
VVAR="some value"
変数が定義されている場合、「定義済変数」と表記。(定義済変数は、空変数か有効値変数のいずれか)
set -u の場合、変数展開時に未定義だとエラーになる。
code:echo
# -> []
# 未定義でエラー
set -u を設定しているときに、以下の方法は使えない。
code:sh(bash)
set -u
echo T
else
echo F
fi
-n は空文字列でなければ真
-z は空文字列なら真
なぜダブルクォーテーションで括らなければならないのというと、変数展開で空白が含まれているとそこで分割されてしまうため。分割された文字列の中にクォーテーションが含まれると壊れる。
code:injection.sh
MYVAR="X"
echo $?
# -> 0
MYVAR="' '"
echo $?
# -> [: ': unexpected operator
# -> 2
シェルスクリプトにはパラメータ展開の記法があり、それを使う場合は、未定義変数でもエラーにならない。
定義されていない場合、"Unset" と表記
定義されているが空文字列の場合、"Set But Null" と表記
定義されていて空文字列ではない場合、"Set and Not Null" と表記
安全に使える組み合わせは "${parameter+word}" または "${parameter:+word}" になる。(ダブルクォーテーションを忘れるとハマる)
code:sh
...
fi
...
fi
...
fi
...
fi
また、以下のように、1文の中で使うことはできない。必ず別の文にする必要がある。
(判定してから展開ではなくて、展開してから判定されるため。)
code:bad.sh
# MYVAR が未定義の場合、エラー。判定より先に展開されてしまう。
code:good.sh
# MYVAR が未定義でも問題ない。判定の後で展開。
printf "%s" "$MYVAR"
fi
判定式を見ても、とてもわかりづらいので、コメントを書くことを推奨する。
前提となる test コマンドと変数展開の挙動について
直接値を評価するのはやや危険なので禁止("x"の有無を評価しているので大丈夫なはずだが)
! を付けると次の結果が反転する。
値を直接評価する場合
0項目の場合は false となる。
1項目の場合
空文字列の場合は false となる。
それ以外の文字列はすべて true となる。
]でも文字列扱いになる。
0, 1も文字列扱いになる。
ダブルクォーテーションで変数展開を括らない場合、変数展開による空文字列は項目ではなくなる。
ダブルクォーテーションで変数展開を括った場合、変数展開による空文字列は項目になる。
Keyword: 変数が定義されているか
関連