我经常在使用自动工具(autoconf,automake)的项目的构建脚本中看到这种情况。当有人要检查shell变量的值时,他们经常使用以下惯用法:
if test "x$SHELL_VAR" = "xyes"; then
...
与像这样简单地检查值相比,这样做有什么好处:
if test $SHELL_VAR = "yes"; then
...
我认为一定有某种原因使我经常看到此消息,但我无法弄清楚它是什么。
我经常在使用自动工具(autoconf,automake)的项目的构建脚本中看到这种情况。当有人要检查shell变量的值时,他们经常使用以下惯用法:
if test "x$SHELL_VAR" = "xyes"; then
...
与像这样简单地检查值相比,这样做有什么好处:
if test $SHELL_VAR = "yes"; then
...
我认为一定有某种原因使我经常看到此消息,但我无法弄清楚它是什么。
X""
。这个问题实际上也是这个问题的重复,或者涵盖了大多数相同的问题。两个重复项都有很好的答案。
Answers:
如果您使用的是执行简单替换的外壳,并且SHELL_VAR
变量不存在(或为空),则需要注意边缘情况。以下翻译将发生:
if test $SHELL_VAR = yes; then --> if test = yes; then
if test x$SHELL_VAR = xyes; then --> if test x = xyes; then
由于第一个参数totest
丢失了,因此第一个将产生错误。第二个没有那个问题。
您的案例翻译如下:
if test "x$SHELL_VAR" = "xyes"; then --> if test "x" = "xyes"; then
的x
,至少对于符合POSIX的壳,实际上是多余的,因为引号随之而来的是两个空的参数和一个容纳空间被解释为单个对象。
test "$SHELL_VAR" = yes
更优雅xyes
?对于期权处理,更改订单'abc' = "$1"
会是另一种选择吗?
test
丢失而不会变成空字符串?不同的外壳处理方式是否不同?
export xxx=''
,if test $xxx = 1 ; then echo 2 ; fi
,export xxx='yyy'
,if test $xxx = 1 ; then echo 2 ; fi
。第一个if
给出错误,第二个不给出错误。这是在bash
。
x
可能在较旧的外壳中使用了它们。
没有人提及的另一个原因与期权处理有关。如果您写:
if [ "$1" = "abc" ]; then ...
并且$ 1的值为'-n',测试命令的语法不明确;不清楚您正在测试什么。前面的“ x”可防止前划线引起麻烦。
您必须查看真正古老的shell才能找到其中一个test命令不支持-n
or的外壳-z
;版本7(1978)test
命令包括它们。并不是很无关紧要-一些版本6 UNIX的内容已经泄漏到BSD中,但是如今,要找到当前使用的古老内容非常困难。
正如许多其他人指出的那样,不对值使用双引号是很危险的。确实,如果文件名中可能包含空格(MacOS X和Windows都在一定程度上鼓励这样做,并且Unix一直支持它,尽管诸如xargs
加大难度),那么您也应在每次使用文件名时将文件名都用双引号引起来。除非您负责该值(例如,在选项处理期间,并且在启动时将变量设置为“ no”,在命令行中包含标志时将变量设置为“ yes”),否则使用不带引号的变量形式是不安全的直到您证明它们是安全的-并且您不妨一直将其用于多种用途。或者记录一下,如果用户尝试处理名称中带有空格的文件,则脚本将严重失败。(还有其他角色也要担心,例如反引号也可能很讨厌。)
test
实现不应输入[-n“ $ var”]分支大小写(仅需要2个参数)。就我个人而言,每次遇到问题时,要么与$ var周围的引号缺失有关,导致错误“ =:期望一元运算符”,要么-z选项不存在,或者test
在其核心[...]内部而不是复杂地使用使用多个[test1] || [test2]在shell级别(如@Jay所述)。
test
确实做了怪异的事情,并且该技术可以防止那些怪异的实现。您可能很幸运,这些天不必担心它。
我知道这个约定有两个原因:
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的”取消)。
其次,在除Bash以外的其他shell中,尤其是较旧的shell中,不存在用于测试空变量的测试条件(例如“ -z”),因此:
if [ -z "$SOME_VAR" ]; then
echo "this variable is not defined"
fi
如果您希望在各种UNIX环境中实现可移植性,而在这些环境中您不能确定默认的shell是Bash且它是否支持-z测试条件,则使用BASH会更安全,如果[ x $ SOME_VAR“ =” x“],因为那样总是可以达到预期的效果。从本质上讲,这是一个用于查找空变量的旧Shell脚本技巧,尽管有更清洁的方法可用,但今天它仍用于向后兼容。
[ -n "$string" ] || [ "$a" = "$b" ]
我建议改为:
if test "yes" = "$SHELL_VAR"; then
因为它摒弃了丑陋的x
,而且还解决了提到的问题https://stackoverflow.com/a/174288/895245即$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$Variable"
。这个问题是这个问题的重复。