我经常在使用autotools(autoconf,automake)的项目的构建脚本中看到这种情况。当有人要检查shell变量的值,他们经常使用这个成语:
if test "x$SHELL_VAR" = "xyes"; then
...
有什么优势,这只是检查像这样的价值在:
if test $SHELL_VAR = "yes"; then
...
我算起来也必须是我经常看到这个的一些原因,但我无法弄清楚它是什么。
我经常在使用autotools(autoconf,automake)的项目的构建脚本中看到这种情况。当有人要检查shell变量的值,他们经常使用这个成语:
if test "x$SHELL_VAR" = "xyes"; then
...
有什么优势,这只是检查像这样的价值在:
if test $SHELL_VAR = "yes"; then
...
我算起来也必须是我经常看到这个的一些原因,但我无法弄清楚它是什么。
如果您使用的是一个壳简单替代和SHELL_VAR
变量不存在(或为空),那么您需要注意边缘情况。下面的转换会发生:因为拳头参数test
不见了
if test $SHELL_VAR = yes; then --> if test = yes; then
if test x$SHELL_VAR = xyes; then --> if test x = xyes; then
其中第一项将产生一个错误。第二个没有这个问题。
你的情况下翻译如下:
if test "x$SHELL_VAR" = "xyes"; then --> if test "x" = "xyes"; then
可能似乎有点多余,因为它具有引号和“×”,但它也将处理与空格的变量,不给作为两个参数到test
命令。
另一个原因(空变量除外)与选项处理有关。如果你写:
if test "$1" = "abc" ; then ...
和$1
具有价值-n
或-z
或任何其他有效的选项为test
命令,语法是不明确的。前方的x
可防止将前导短跑选作test
的选项。
请记住,这取决于外壳。有些shell(csh
,我认为)如果环境变量不存在而不是仅仅返回一个空字符串,会很痛苦地抱怨)。
是的,现在看起来很明显。 – jonner 2008-10-06 13:57:20
我曾经在DOS下做过SHELL_VAR可能未定义的情况。
我相信它是由于
SHELLVAR=$(true)
if test $SHELLVAR = "yes" ; then echo "yep" ; fi
# bash: test: =: unary operator expected
以及
if test $UNDEFINEDED = "yes" ; then echo "yep" ; fi
# bash: test: =: unary operator expected
和
SHELLVAR=" hello"
if test $SHELLVAR = "hello" ; then echo "yep" ; fi
# yep
然而,这通常应该工作
SHELLVAR=" hello"
if test "$SHELLVAR" = "hello" ; then echo "yep" ; fi
#<no output>
但是当它在输出抱怨别的地方,它很难说其抱怨我猜,所以
SHELLVAR=" hello"
if test "x$SHELLVAR" = "xhello" ; then echo "yep" ; fi
作品一样好,但会更容易调试。
如果你不做“x $ SHELL_VAR”的事情,那么如果$ SHELL_VAR未定义,你会得到一个关于“=”不是一个monadic操作符或类似的错误。
有两方面的原因,我知道这个约定:
http://tldp.org/LDP/abs/html/comparison-ops.html
在混合测试,甚至引用字符串变量可能是不够的。如果$ string为空, [-n“$ string”-o“$ a”=“$ b”]可能会导致某些版本的 Bash出错。安全的方法是向可能为空的变量追加一个额外的字符,[“x $ string”!= x -o“x $ a”=“x $ b”](“x's”抵消)。
其次,在其他壳比猛砸,尤其是老年人,喜欢的测试条件“-z”来测试一个空的变量是不存在的,因此,虽然这样的:
if [ -z "$SOME_VAR" ]; then
echo "this variable is not defined"
fi
将正常工作在BASH中,如果你的目标是跨越各种UNIX环境的可移植性,在这些环境中你不能确定默认shell是Bash,并且它是否支持-z测试条件,那么使用if [“x $ SOME_VAR “=”x“],因为这将始终具有预期的效果。从本质上讲,这是一个用于查找空变量的旧shell脚本技巧,尽管存在更简洁的方法,但它现在仍然用于向后兼容。
另一个没有人提到的原因是与选项处理有关。如果你写:
if [ "$1" = "abc" ]; then ...
和$ 1的值为'-n',测试命令的语法不明确;目前还不清楚你正在测试什么。前面的'x'可防止前导破折号引起麻烦。
你必须看着真正古老的炮弹找到一个测试命令不支持-n
或-z
;版本7(1978)test
命令包含它们。这并不是无关紧要的 - 一些版本6 UNIX的东西被转移到了BSD中,但是现在你很难找到任何古老的东西。
正如许多其他人所指出的那样,在值周围不使用双引号是很危险的。事实上,如果文件名可能包含空格(MacOS X和Windows都在某种程度上鼓励,而且Unix一直支持它,尽管像xargs
这样的工具使得它更难),那么你应该把文件名用双引号括起来你也可以使用它们。除非你负责该值(例如在选项处理过程中,并且在启动时将该变量设置为'no',而在命令行中包含标志时将该变量设置为'yes'),那么使用不加引号的变量形式是不安全的直到你证明他们是安全的 - 而且你也可以一直做很多事情。或者如果用户试图处理名称中空白的文件,那么你的脚本将会非常糟糕地失败。 (还有其他人物也会担心 - 例如,反引号也可能相当讨厌。)
我建议改为:
if test "yes" = "$SHELL_VAR"; then
因为它摒弃了丑陋x
,还解决了https://stackoverflow.com/a/174288/895245提到的问题可-
开始,被解读为一种选择。
请参阅参考[shell脚本在``x $ Variable'``]中的用途“(http://stackoverflow.com/questions/1805663/shell-script-purpose-of-x-in-xvariable/)。这个问题是这个问题的重复。 – 2013-12-29 16:37:16
另请参阅[使用``X``测试空字符串``](http://stackoverflow.com/questions/6852612/bash-test-for-empty-string-with-x)。这个问题实际上也是这个问题的重复,或者涵盖了大部分相同的理由。这两个副本都有一些很好的答案。 – 2013-12-29 16:45:51