我知道我可以使用-z
测试Bash中的空字符串,如下所示:
if [[ -z $myvar ]]; then do_stuff; fi
但我看到很多代码写得像:
if [[ X"" = X"$myvar" ]]; then do_stuff; fi
这种方法更便携吗?这只是-z
之前的历史残余吗?它适用于POSIX shell(尽管我已经看到它用于定位bash
的脚本中)?准备好我的历史/便携性课程。
同样的问题在服务器故障上被称为How to determine if a bash variable is empty?,但是没有人提供关于为什么您看到带有X""
内容的代码的解释。
答案 0 :(得分:116)
从根本上说,因为在很久以前的时间里,test
的行为更复杂,并且在不同的系统中没有统一定义(因此必须仔细编写可移植代码以避免不可移植的构造)。
特别是,在test
是内置shell之前,它是一个单独的可执行文件(请注意,MacOS X仍然有/bin/test
和/bin/[
作为可执行文件)。在这种情况下,写下:
if [ -z $variable ]
当$variable
为空时,将通过带有3个参数的别名[
调用测试程序:
argv[0] = "["
argv[1] = "-z"
argv[2] = "]"
因为变量是空的所以没有任何东西可以扩展。因此,编写代码的安全方法是:
if [ -z "$variable" ]
这可靠地工作,将4个参数传递给test
可执行文件。几十年来,测试程序已经成为大多数炮弹的内置物,但旧设备很难消失,所以很久以前就会学到很好的实践。
X前缀解决的另一个问题是,如果变量包含前导破折号,或包含等号或其他比较符,则会发生这种情况。考虑(一个不是绝对好的例子):
x="-z"
if [ $x -eq 0 ]
这是一个带有迷路(错误)参数的空字符串测试,还是带有非数字第一个参数的数字相等测试?在POSIX标准化行为之前,不同的系统提供了不同的答案,大约在1990年。因此,处理这个问题的安全方法是:
if [ "X$x" = "X0" ]
或(通常情况下,根据我的经验,但完全相同):
if [ X"$x" = X"0" ]
这是所有类似的边缘情况,与测试是一个单独的可执行文件的可能性捆绑在一起,这意味着可移植shell代码仍然比现代shell实际需要更多地使用双引号,以及X前缀表示法用来确保事情不会被误解。
答案 1 :(得分:11)
X
开头,则设置-
,可以将其作为测试的标志。在之前放置X
只会删除该情况,并且比较仍然可以保留。
我也喜欢这个,因为这种技巧几乎是过去,最古老的计算时代的继承,当你尝试阅读一些最便携的shell脚本时会遇到它(autoconf,configure等)。 )