使用X""对空字符串进行Bash测试

mga*_*lgs 75 string bash shell posix

我知道我可以在Bash中测试一个空字符串,-z如下所示:

if [[ -z $myvar ]]; then do_stuff; fi
Run Code Online (Sandbox Code Playgroud)

但我看到很多代码写得像:

if [[ X"" = X"$myvar" ]]; then do_stuff; fi
Run Code Online (Sandbox Code Playgroud)

这种方法更便携吗?它只是在日子之前的历史残余-z吗?它适用于POSIX shell(即使我已经看到它用于脚本定位bash)?准备好我的历史/可移植性课程.


在服务器故障上询问的问题是如何确定bash变量是否为空?但没有人提供解释为什么你看到代码与X""东西.

Jon*_*ler 118

从根本上说,因为在很久以前的时间里,行为test更复杂,并且在不同的系统中没有统一定义(因此必须仔细编写可移植代码以避免非便携式构造).

特别是,之前test是一个shell内置,它是一个独立的可执行文件(请注意,MacOS X系统仍然有/bin/test/bin/[为可执行文件).在那种情况下,写下:

if [ -z $variable ]
Run Code Online (Sandbox Code Playgroud)

when $variable为空时,将通过[带有3个参数的别名调用测试程序:

argv[0] = "["
argv[1] = "-z"
argv[2] = "]"
Run Code Online (Sandbox Code Playgroud)

因为变量是空的所以没有什么可以扩展.因此,编写代码的安全方法是:

if [ -z "$variable" ]
Run Code Online (Sandbox Code Playgroud)

这可靠地工作,将4个参数传递给test可执行文件.当然,几十年来,测试程序已经成为大多数炮弹的内置物,但是旧设备很难消失,所以很久以前就会学到很好的实践.

X前缀解决的另一个问题是,如果变量包含前导破折号,或者包含等号或其他比较符,则会发生这种情况.考虑(一个不是绝对好的例子):

x="-z"
if [ $x -eq 0 ]
Run Code Online (Sandbox Code Playgroud)

这是一个带有迷路(错误)参数的空字符串测试,还是带有非数字第一个参数的数字相等测试?在POSIX标准化行为之前,不同的系统提供了不同的答案,大约在1990年.因此,处理这个问题的安全方法是:

if [ "X$x" = "X0" ]
Run Code Online (Sandbox Code Playgroud)

或者(通常,根据我的经验,但完全相同):

if [ X"$x" = X"0" ]
Run Code Online (Sandbox Code Playgroud)

这是所有这样的边缘情况,与测试是一个单独的可执行文件的可能性相关,这意味着可移植shell代码仍然比现代shell实际需要更多地使用双引号,并且X前缀表示法用于确保事情不会被误解.

  • 大多数(也许是所有)类Unix系统仍然具有"测试"和"["可执行文件(在Ubuntu上,它们位于/ usr/bin中,不在/ bin中).这允许它们从shell脚本以外的东西中使用.(请参阅系统的文档;该命令可能与shell内置的行为略有不同 - 它本身可能因shell而异.) (5认同)

Die*_*lla 11

啊,这是我喜欢的问题和答案之一,因为我想出了答案.该X设置以防万一字符串以a开头-,可以采取作为测试的标志.放一个X之前只是删除了这种情况,并且比较仍然可以保持.

我也喜欢这个,因为这种技巧几乎是过去,最古老的计算时代的继承,当你尝试阅读一些最便携的shell脚本时,你会遇到它(autoconf,configure等)

  • @mitch:是的,也许它不会在“-z”处失败,但它被用作(我可能认为是出于习惯)只是作为所有字符串比较的标记。 (2认同)