我发现一个脚本有一个函数来检查变量是否已设置,但我不太理解它。
check_if_variable_is_set() {
var_name=$1
if [ -z "${!var_name+x}" ]; then
false
else
true
fi
}
这个替换到底会发生什么?
答案1
在bash
shell中,${!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
是bash
对变量名称的测试,如果设置了命名变量,则为 true,否则为 false。
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:]]
将检查字母字符在您所在的地区而某些 shell 仅接受其变量中可移植字符集中的字母字符)