我知道我可以在 Bash 中使用 -z
测试空字符串,如下所示:
if [[ -z $myvar ]]; then do_stuff; fi
但是我看到很多代码是这样写的:
if [[ X"" = X"$myvar" ]]; then do_stuff; fi
那个方法更便携吗?这只是 -z
时代之前的历史遗留问题吗?它是否用于 POSIX shell(尽管我已经看到它用于针对 bash
的脚本)?为我的历史/便携性类(class)做好准备。
在 Server Fault 上提出了与 How to determine if a bash variable is empty? 相同的问题但没有人解释为什么您会看到带有 X""
内容的代码。
从根本上说,因为在很久以前,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
可执行文件。诚然,测试程序几十年来一直是大多数 shell 的内置程序,但旧设备经久耐用,更早以前学到的良好做法也是如此。
X 前缀解决的另一个问题是,如果变量包含前导破折号,或包含等号或其他比较器,会发生什么情况。考虑(一个不太好的例子):
x="-z"
if [ $x -eq 0 ]
这是带有杂散(错误)参数的空字符串测试,还是带有非数字第一个参数的数字相等性测试?在大约 1990 年 POSIX 标准化行为之前,不同的系统提供了不同的答案。因此,处理这个问题的安全方法是:
if [ "X$x" = "X0" ]
或(根据我的经验,不太常见,但完全等同):
if [ X"$x" = X"0" ]
所有的边缘情况都是这样的,与测试是一个单独的可执行文件的可能性相关联,这意味着可移植的 shell 代码仍然比现代 shell 实际需要的更大量地使用双引号,以及 X 前缀符号用于确保事情不会被误解。