例如,当运行以下shell脚本时:
foo="example"
if [ -o $foo ]; then
foo="true"
echo $foo
fi
结果为false,不返回任何内容。
但是如果foo的值为null
foo=" "
if [ -o $foo ]; then
foo="true"
echo $foo
fi
返回真值。
操作foo = "example"如果[$foo -o $foo]在shell脚本中是可以理解的。(I understand that value is true.)
然而,如果foo = "abc"如果[-o $foo],我将其理解为null或true ($foo value)。
结果是错误的,与我的期望相反。
这是什么原因?
一些事实:
- 在bash中,
[ -o OPTION ]
中的-o
是测试shell选项option是否被启用的操作符。 [ STRING ]
测试STRING是否为空。- 内部单括号(
[ ]
),如果$foo
没有被引用,它将进行分词。
:
- 对于
foo=' '; [ -o $foo ]
,执行的测试是[ -o ]
。-o
不是空字符串,所以它返回true。 opt=posix; set -o $opt; [ -o $opt ]
返回true,因为设置了选项posix
。opt=posix; set +o $opt; [ -o $opt ]
返回false,因为选项posix
未设置。
在双括号测试语法中,不发生分词。所以在foo=' '; [[ -o $foo ]]
中,空间是保留的。执行的测试是[[ -o <space> ]]
,它返回false,因为
我建议使用双括号,除非你有很好的理由不这么做。单括号测试语法主要是为了兼容POSIX和遗留的bourne shell脚本。
如果您使用单括号,请引用所有变量,以防止分词和全局展开(这不会发生在双括号内)。
阅读bash源代码:
案例1:foo="example"; [ -o $foo ]
→[ -o example ]
案例1 b:foo=""; [ -o "$foo" ]
→[ -o □ ]
- 使用□表示参数为空字符串
- 解析为两个参数
- 第一个参数(
-o
)匹配一元操作符"find_option_o_value"> - 第二个参数不是有效的选项名
- 结果:false(未找到)
- 注意:当第二个参数是一个有效的选项名时,返回值将指示该选项是否被设置(true⇒enabled, false⇒disabled)
案例2:foo=" "; [ -o $foo ]
→[ -o ]
案例2 b:foo=" "; [ $foo -o $foo ]
→[ -o ]
- 解析为一个参数
- 参数(
-o
)是非空 - 结果:真正的
案例3:foo=""; [ "$foo" -o "$foo" ]
→[ □ -o □ ]
- 使用□表示参数为空字符串
- 解析为三个参数
- 第二个参数是ANDOR运算符
- 第一个和第三个参数都不为非空
- 结果:假
案例4:foo=""; [ "$foo" -o $foo ]
→[ □ -o ]
- 使用□表示参数为空字符串
- 解析为两个参数
- 第一个参数不是一元操作符
- result: false(语法错误)
如果不引用变量,并且变量为空,或者只有空白(即$IFS中的空白),则命令根本看不到。所以test -o $foo和test -o
是一样的我不认为它返回true有什么特别好的理由,你所做的是病态的,没有任何意义。你需要做的是对变量加双引号,这样可以保证测试可以看到这里有一些东西,然后它会对它做一些合理的处理。作为一般规则,总是双引号的东西,你通过测试,以防万一它是空的。