使用 [[

使用 [[

我正在看 Kusalananda 和 xhienne 之间的讨论这里,其中提到这不是一个有效的测试,会在其他 POSIX 兼容 shell[ "" -ge 2 ]中产生错误。bash --posix

bash-4.3$ [ "" -gt 10 ]
bash: [: : integer expression expected
bash-4.3$ [ '' -gt 10 ]
bash: [: : integer expression expected

那里一切都好。出于好奇,我尝试了同样的操作[[

bash-4.3$ [[ "" -gt 10 ]] && echo "YES"
bash-4.3$ [[ "" -gt 0 ]] && echo "YES"
bash-4.3$ [[ "" -gt -1 ]] && echo "YES"
YES
bash-4.3$ [[ "" -eq 0 ]] && echo "YES"
YES

正如您所看到的,没有错误,它实际上被计算为数字表达式,其中“”等于 0。那么这里到底发生了什么?[[仅仅是与旧的test或 POSIX不一致吗?它只是执行字符串比较而不是数字比较吗?

答案1

[和之间的一个区别[[[之间不是进行算术评估,但[[会:

$ [ "2 + 2" -eq 4 ] && echo yes
bash: [: 2 + 2: integer expression expected
$ [[ "2 + 2" -eq 4 ]] && echo yes
yes

第二个微妙之处是,无论在哪里算术评估在 bash 下执行,空字符串的计算结果为 0。例如:

$ x=""; echo $((0 + x))
0
$ [[ "" -eq 0 ]] && echo yes
yes

文档

man bash

允许 Shell 变量作为操作数;参数扩展在计算表达式之前执行。在表达式中,shell 变量也可以通过名称引用,而不使用参数扩展语法。当通过名称引用而不使用参数扩展语法时,为 null 或未设置的 shell 变量的计算结果为 0。当引用变量时,或者当为使用声明 -i 赋予整数属性的变量赋值时,变量的值将被计算为算术表达式。 空值的计算结果为 0。 shell 变量无需打开其整数属性即可在表达式中使用。 [添加了强调]

旁白:安全问题

请注意,bash 的算术评估是一个潜在的安全问题。例如,考虑:

x='a[$(rm -i *)]'
[[ x -eq 0 ]] && echo yes

使用该-i选项,上述操作是安全的,但一般教训是不要对未经净化的数据使用 bash 的算术评估。

相比之下,使用 时[,不会执行算术评估,因此该命令从不尝试删除文件。相反,它会安全地生成错误:

$ x='a[$(rm -i *)]'
$ [ "$x" -eq 0 ] && echo yes
bash: [: a[$(rm -i *)]: integer expression expected

有关此问题的更多信息,请参阅这个答案

答案2

是的,在数值比较中 posix test ( [) 不会将字符串转换为数字:

$ sh -c '[ 2+2 -eq 4 ]'
sh: 1: [: Illegal number: 2+2

$  dash -c '[ 2+2 -eq 4 ]'
dash: 1: [: Illegal number: 2+2

$ bash -c '[ 2+2 -eq 4 ] && echo "YES"'
bash: line 0: [: 2+2: integer expression expected

然而,并非所有 shell 都以相同的方式工作:

$ ksh -c '[ 2+2 -eq 4 ] && echo "YES"'
YES

通常的解决方法

确保将 null 或空值转换为 0(适用于大多数 shell)

$ dash -c 'a=""; [ "${a:-0}" -gt 3 ] && echo "YES"'

使用算术

使用算术扩展(也可以像2+2在某些 shell 中那样转换值(不是破折号))

$ dash -c 'a=""; [ "$((a+0))" -gt -3 ] && echo "YES"'
YES

使用 [[

使用该[[测试将转换大多数字符串,这些字符串将在允许的 shell 中变成数字(即使不需要)[[

$ [[ "2+2" -gt 3 ]] && echo "YES"
YES

相关内容