将变量值与某物进行比较时(我将进行算术比较,这样您就不能使用"x$VAR" == "xyes"
诡计),当变量包含空格和/或 shell 语法时,如何防止出现这种情况?
$ (b="-z foo"; if [[ "$b" -eq 5 ]]; then echo foo; fi)
+(:50): b='-z foo'
+(:50): [[ -z foo -eq 5 ]]
-bash: [[: -z foo: syntax error in expression (error token is "foo")
尝试过:单括号和双括号、算术评估 ( (())
)、引用和不引用、"${b##-}"
、 甚至"${b@Q}"
;检查过https://mywiki.wooledge.org/BashPitfalls。
答案1
当一个值需要是十进制整数并且我不希望用户遇到令人困惑的错误和脚本中止事件时,我会测试该变量是否存在非数字字符并使用我自己的错误消息处理它:
[[ -z ${val} ]] && {
echo "$0: Oops, \"${val}\" is empty" >&2
exit 1
}
[[ ${val} =~ [^[:digit:]] ]] && {
echo "$0: Oops, non-numeric characters found in \"${val}\"" >&2
exit 1
}
如果该值是不需要空格的字符串,我将使用类似的技术来检查空格:
[[ ${val} =~ [[:blank:]] ]] && {
echo "$0: Oops, \"${val}\" contains space or tab characters" >&2
exit 1
}
如果您还想测试换行符、回车符、换页符和垂直制表符,请使用[:space:]
字符类。
这就是我在 bash v4.x 脚本中所做的事情。对于其他 shell,我没有什么建议可以提供。
答案2
在[[ ... ]]
ksh 构造中(由包括 bash 在内的一些 shell 复制,但有变体),算术运算符的操作数被解释为算术表达式,并且如果不进行清理,则使用外部提供的输入会引入任意执行漏洞。
同样适用于(( a == b ))
(也来自 ksh)。
为了避免这种情况,您需要决定要接受什么输入,要么手动进行清理并拒绝任何与您想要的不匹配的内容,要么使用除仅[[ ... ]]
接受您想要允许的格式的常量之外的命令。
如果您只想在 bash 和其他一些 shell 中允许带有可选前导符号的十进制整数常量,并且可能周围有空格,则可以使用仅接受十进制整数的[
aka内置函数。test
[ "$b" -eq 5 ]
如果$b
不是十进制整数常量,[
则会失败并显示错误并返回状态 2。
要允许 POSIX 指定的所有算术表达式常量(例如 12、-1、010、0x5),您可以采用dash
仅接受算术表达式内的裸变量的方式,如果它们包含常量或空字符串(可以选择用空格包围) 。
VAL="$b" dash -c '[ "$((VAL))" -eq 5 ]'
$b
(如果不包含有效常量,则状态再次为 2 )。
要允许更多数字,例如 1.123(在某些语言环境和某些 awk 实现中可能为 1,123)、50e-1 甚至更多,您可以使用awk
:
awk -- 'BEGIN{exit !(ARGV[1] == 5)}' "$b"
在那里,如果$b
不被识别为数字,则将执行字符串比较,返回 false。使用 GNU,您可以通过检查 if returnsawk
来判断字符串是否被识别为数字。typeof(ARGV[1])
strnum
还要注意范围和精度。 4.9999999999999999 或 18446744073709551621 (2 64 +5) 可能被认为与 5 相同,具体取决于您询问的对象。