変数が設定されていることを確認する機能を持つスクリプトが見つかりましたが、よく理解されていません。
check_if_variable_is_set() {
var_name=$1
if [ -z "${!var_name+x}" ]; then
false
else
true
fi
}
今回の交換で正確に何が起こりますか?
答え1
bash
シェルでは、${!var}
変数間接アドレス指定です。に名前がある変数の値に展開されます$var
。
変数拡張${var+value}
はPOSIX拡張value
変数が設定されている場合var
(その値が空であるかどうかにかかわらず)、拡張されます。
これを組み合わせると、名前が格納された変数が${!var+x}
設定されるかどうかが拡張されます。x
$var
例:
$ foo=hello
$ var=foo
$ echo "${!var+$var is set, its value is ${!var}}"
foo is set, its value is hello
$ unset foo
$ echo "${!var+$var is set, its value is ${!var}}"
(出力で空白行)
問題の機能は、次のように短縮できます。
check_if_variable_is_set () { [ -n "${!1+x}" ]; }
でも:
check_if_variable_is_set () { [ -v "$1" ]; }
でも:
check_if_variable_is_set()[[ -v $1 ]]
変数名のテストはどこに-v
ありますか?名前付き変数が設定されている場合はtrue、それ以外の場合はfalsebash
POSIXlyでは、次のように書くことができます。
check_if_variable_is_set() { eval '[ -n "${'"$1"'+x}" ]'; }
関数のパラメータが攻撃者の制御下に入る可能性がある場合、これらはすべて潜在的なコマンド注入の脆弱性であることに注意してください。たとえばcheck_if_variable_is_set 'a[$(id>&2)]'
。
これを防ぐには、まず引数が有効な変数名であることを確認することをお勧めします。変数の場合:
check_if_variable_is_set() {
case $1 in
("" | *[![:alnum:]_]* | [![:alpha:]_]*) false;;
(*) eval '[ -n "${'"$1"'+x}" ]'
esac
}
([[:alpha:]]
アルファベット文字は確認されます。あなたの地域で一部のシェルは、変数の移植可能な文字セットからアルファベット文字のみを受け入れます。