壳相等运算符(=,==,-eq)

在shell脚本中,===-eq之间的区别是什么?

下面这些有什么区别吗?

[ $a = $b ]
[ $a == $b ]
[ $a -eq $b ]

仅仅是因为===只在变量中包含数字时才被使用吗?

392171 次浏览

===用于字符串比较
-eq用于数值比较
-eq-lt-le-gt-ge-ne

属于同一个家族

==是特定于bash的(在sh (Bourne shell)中不存在,…)出于兼容性考虑,首选使用POSIX =。在bash中,这两个是等价的,在sh =中是唯一可以工作的。

$ a=foo
$ [ "$a" = foo ]; echo "$?"       # POSIX sh
0
$ [ "$a" == foo ]; echo "$?"      # bash-specific
0
$ [ "$a" -eq foo ]; echo "$?"     # wrong
-bash: [: foo: integer expression expected
2

(注意:确保引用变量展开。不要漏掉上面的双引号。)

如果你正在编写#!/bin/bash脚本,那么我推荐使用[[代替。双方括号[[...]]形式有更多的功能,更自然的语法,更少的陷阱会绊倒你。例如,在$a周围不再需要双引号:

$ [[ $a == foo ]]; echo "$?"      # bash-specific
0

参见:

===的bash特定别名,它执行字符串(词法)比较而不是数值比较。eq当然是一个数值比较。

最后,我通常更喜欢使用if [ "$a" == "$b" ]形式

它取决于操作符周围的测试构造。你的选项是双括号、双括号、单括号或test

如果你使用__ABC0…)),你是在用C中的==测试算术相等性:

$ (( 1==1 )); echo $?
0
$ (( 1==2 )); echo $?
1

(注意:0在Unix意义上表示true,失败的测试结果是非零数字。)

在双括号内使用-eq是一个语法错误。

如果你使用]1(或单括号)或]2(或双括号)或test,你可以使用-eq-ne-lt-le-gt]0中的一个作为]3。

$ [ 1 -eq 1 ]; echo $?
0
$ [ 1 -eq 2 ]; echo $?
1
$ test 1 -eq 1; echo $?
0

单括号或双括号(或test命令)内的==字符串比较操作符中的一个:

$ [[ "abc" == "abc" ]]; echo $?
0
$ [[ "abc" == "ABC" ]]; echo $?
1

作为字符串操作符,=等价于==。另外,注意===周围的空格:这是必需的。

当你可以执行[[ 1 == 1 ]][[ $(( 1+1 )) == 2 ]]时,它是在测试字符串相等-而不是算术相等。

所以-eq产生的结果可能期望1+1的整数值等于2,即使右边是一个字符串并且有一个尾随空格:

$ [[ $(( 1+1 )) -eq  "2 " ]]; echo $?
0

而相同的字符串比较会选择尾随空格,因此字符串比较失败:

$ [[ $(( 1+1 )) == "2 " ]]; echo $?
1

错误的字符串比较可能会产生完全错误的答案。10是小于2字母顺序,所以字符串比较返回true0。很多人都被这个问题所困扰:

$ [[ 10 < 2 ]]; echo $?
0

10小于2的正确测试是:

$ [[ 10 -lt 2 ]]; echo $?
1

在注释中,有一个关于技术的问题,为什么在字符串上使用整数-eq对于不相同的字符串返回true:

$ [[ "yes" -eq "no" ]]; echo $?
0

原因是Bash是无类型-eq使字符串被解释为整数如果可能的话,包括基本转换:

$ [[ "0x10" -eq 16 ]]; echo $?
0
$ [[ "010" -eq 8 ]]; echo $?
0
$ [[ "100" -eq 100 ]]; echo $?
0

0如果Bash认为它只是一个字符串:

$ [[ "yes" -eq 0 ]]; echo $?
0
$ [[ "yes" -eq 1 ]]; echo $?
1

所以[[ "yes" -eq "no" ]]等价于[[ 0 -eq 0 ]]


最后一个注释:测试构造的许多Bash特定扩展都不是POSIX,因此在其他shell中可能会失败。其他shell通常不支持__ABC0和__ABC1或==

有几个答案给出了危险的例子。OP的例子[ $a == $b ]特别使用了不带引号的变量替换(截至2017年10月编辑)。对于[...],对于字符串相等是安全的。

但是如果你要枚举像[[...]]这样的替代选项,你还必须通知右边必须被引用。如果没有引用,则是模式匹配!(来自Bash手册页:“模式的任何部分都可以被引用,以强制将其作为字符串进行匹配。”)。

在Bash中,产生“yes”的两个语句;是模式匹配,其他三个是字符串相等:

$ rht="A*"
$ lft="AB"
$ [ $lft = $rht ] && echo yes
$ [ $lft == $rht ] && echo yes
$ [[ $lft = $rht ]] && echo yes
yes
$ [[ $lft == $rht ]] && echo yes
yes
$ [[ $lft == "$rht" ]] && echo yes
$