以下脚本的行为与我的预期不同。在条件语句中的“=”周围添加空格使其按照我想要的方式执行,但这让我思考,它在条件语句中实际上在做什么?
#!/bin/bash
S1='foo'
S2='bar'
if [ $S1=$S2 ];
then
echo "S1('$S1') is equal to S2('$S2')
fi
echo $S1
echo $S2
输出是:
S1('foo') is equal to S2('bar')
foo
bar
S1 和 S2 的内容不会改变它们被分配的内容,因此 = 不执行分配。
答案1
记住这[
实际上是一个命令,也可以作为test
.在 bash 中,就像在大多数其他类似 Bourne 的 shell 中一样,它是一个内置命令,因此您可以使用info bash [
或 通过在内部搜索来查看文档man bash
(也在man builtin
某些系统上,其中 bash 也是系统的sh
)。
在该文档中:
test
并[
使用基于参数数量的一组规则来评估条件表达式。
- 0 个参数
表达式为假。- 1 参数
当且仅当参数不为空时,表达式才为真。- 2 个参数
[...]- 3 个参数
[...]
迂腐地说,当使用[
而不是test
命令时,最后的(必需的)]
是还一个参数,但这不计入上面的数字(直接来自 bash 文档)。反正...
二参数规则是各种测试,三参数规则一般是比较。当您在 周围添加一个空格时=
,您会得到三个参数。但当你把它们放在一起时,你会得到一参数,如您所见,如果该参数不为 null,则返回 true。
好吧,从技术上讲,由于您忘记了参数扩展周围的引号[ $S1=$S2 ]
(以及其他地方),$S1
并且$S2
受到 split+glob 的影响,因此可能会导致更多参数传递给[
命令。在 bash 中,就像在 ksh 中一样,这甚至会构成命令注入漏洞。
例如,如果$S1
被定义为S1='-v xx[$(reboot)] -o yy'
和$S2
as S2='zz'
,分割部分,默认值为$IFS
yield -v
, xx[$(reboot)]
, -o
, yy=zz
;[...]
作为一个通配符,如果当前目录中有这样的文件,则xx[$(reboot)]
可以扩展为,但如果没有,则将按原样传递到 ,并且在 bash 的内置函数中是一个测试,用于检查数组元素是否已设置,并且是否会扩展根据命令的输出来确定索引。xxo
xxt
xx[$(reboot)]
[
-v array[index]
[
$(reboot)
reboot
正确的语法是[ "$S1" = "$S2" ]
,其中不要忘记引号也很重要。
答案2
在这种情况下,等于运算符不执行任何操作。
该表达式$S1=$S2
计算为实际字符串,其中S1
和的值就位S2
,实际上是字符串文字foo=bar
。
由于该字符串文字不为空,因此语句
if [ "foo=bar" ];
计算结果为 true,并且执行 if 语句的主体。