Bash等式运算符(==,-eq)


135

有人可以解释一下-eq==bash脚本之间的区别吗?

以下内容之间有什么区别吗?

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

难道仅仅是==仅用于当变量包含数字?

Answers:


186

这是周围的其他方法:===用于字符串比较,-eq是数字的。-eq在同一家庭-lt-le-gt-ge,和-ne,如果这能帮助你记住哪个是哪个。

==顺便说一下,这是一种bash-ism。最好使用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

也可以看看:


1
@DJCrashdummy,[[总体而言是bash(以及许多其他外壳)采用的1980年代的ksh-ism。这是整点-如果你有[[ 在所有的,那么你可以安全地假定所有分机KSH周围(实现fnmatch()风格的模式匹配,与ERE正则表达式=~,是的,串分裂的抑制和文件系统通配)会可用。由于[[全部是非POSIX语法,因此假设它所具有的功能将可用就不会造成额外的可移植性损失。
查尔斯·达菲

1
@DJCrashdummy,...链接你正确显示指出,报价有时需要在右边[[ $var = $pattern ]],如果你想要的东西,否则会被解释为一个的fnmatch模式,而不是被解释为一个字符串。该字符串foo没有非文字上的解释,从而使引号完全安全。仅当OP想要匹配时才需要foo*foo引号或转义符(例如,星号为原义,不表示字符串后可能出现的任何内容)。
Charles Duffy

不幸的是,@ CharlesDuffy我不知道您指的是什么,因为我的评论似乎已被删除,我记不清了,因为已经有一段时间了。:-(
DJCrashdummy

@DJCrashdummy,...呵呵,我以为你自己撤了它。基本上,这是对内部引用[[的无用扩展表示反对(表示这是您不给答案+1的唯一原因)。
查尔斯·达菲

@CharlesDuffy不,不是唯一的原因:除了我不喜欢bash-isms,ksh-isms等用于简单任务的事实(这会引起麻烦并混淆初学者),我不明白为什么混用单大括号[ ... ]和双等号==。:-/
DJCrashdummy

27

这取决于操作员周围的测试构造。您可以选择双括号,双括号,单括号或测试

如果您使用((...)),您正在使用==C中的来测试算术净值:

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

(注意:在Unix上0表示平均值true,非零表示测试失败)

使用-eq双括号里面是一个语法错误。

如果您使用[...](或单括号)或[[...]](或双括号),或者test可以使用-eq,-ne,-lt,-le,-gt或-ge作为算术比较

$ [ 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 ]]正在测试字符串相等性-而不是算术相等性。

因此,即使RH是一个字符串并且具有一个尾随空格,它也会-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如果猛砸认为它只是一个字符串:

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

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

最后说明:测试构造的许多Bash特定扩展不是POSIX,因此在其他Shell中将失败。其他壳通常不支持[[...]]((...))==


我对返回True 的技术原因感到好奇[[ "yes" -eq "no" ]]。bash如何将这些字符串强制转换为可以比较的整数值?;-)
odony

4
Bash变量是无类型的,因此[[ "yes" -eq "no" ]]等于[[ "yes" -eq 0 ]][[ "yes" -eq "any_noninteger_string" ]]-全部为True。该-eq部队整数比较。将"yes"被解释为整数0;如果另一个整数是0或字符串结果是,则比较为True 0
dawg

Boo,嘶嘶作响:==在代码示例中显示(非便携式),并且仅=在下面提及(便携式,标准化)。
查尔斯·达菲,

24

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

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


15
==此处使用的格式不正确,仅=由POSIX指定。
查尔斯·达菲,2015年

9
如果您真的坚持要使用,==则将其放在[[和之间]]。(并确保脚本的第一行指定使用/bin/bash。)
holgero 2015年

18

伙计们:几个答案显示了危险的例子。OP的示例[ $a == $b ]专门使用了无引号的变量替换(截至17年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
$

2
即使是为了平等,也需要[ "$lht" = "$rht" ] 与引号保持一致。如果您有创建的文件touch 'Afoo -o AB'[ $lft = $rht ]将返回true,即使该文件的名称是不是在所有相同AB
查尔斯·达菲,
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.