shell 比较中的单等号和双等号 (=) 有什么区别?

use*_*539 52 bash shell-script

为了比较里面的字符串,if我们需要使用双方括号。有些书说比较可以通过=. 但它也适用于==

#!/bin/bash
a="hello"
b="world"
if [[ $a == $b ]];then
    echo "equal"
fi
Run Code Online (Sandbox Code Playgroud)

比较===比较有区别吗?

Sté*_*las 54

[[ $a == $b ]]不是比较,而是模式匹配。您需要[[ $a == "$b" ]]进行字节到字节的相等比较。===任何支持[[...]](由 引入ksh)的shell相同。

[[...]]不是标准sh语法。的[ 命令是标准的,并且标准的比较操作符有=(尽管一些[实施方式中还认识==¹)。

就像在任何命令的任何参数中一样,必须引用变量扩展以防止split+glob和空删除(仅后者在 中执行zsh),因此:

[ "$a" = "$b" ]
Run Code Online (Sandbox Code Playgroud)

在标准中sh,模式匹配是通过以下方式完成的case

case $a in
  ($b) ...
esac
Run Code Online (Sandbox Code Playgroud)

为了完整起见,您可能会在 shell 脚本中遇到其他类似等式的运算符:

  • [ "$a" -eq "$b" ]:[比较十进制整数的标准运算符。有些[实现允许数字周围有空格,有些允许任意算术表达式,但这不是可移植的。便携,可以使用[ "$(($a))" -eq "$(($b))" ]它。另请参阅[ "$((a == b))" -ne 0 ]以下标准等效项(除了 POSIXly,仅当$a$b包含整数常量时才指定行为):

  • ((a == b))从KSH以及在发现zshbash,返回true如果存储在算术表达式的评估$a产率相同的数量的$b。通常,这用于比较数字。请注意,shell 之间在如何计算算术表达式以及支持哪些数字方面存在差异(例如,bash 和 ksh 的某些实现/版本不支持浮点数或将带前导零的数字视为八进制)。

  • expr "$a" = "$b"如果两个操作数都被识别为十进制整数(有些允许数字周围有空格),则进行数字比较,否则检查两个字符串运算符是否具有相同的排序顺序。对于$a或像, ...$b这样的expr运算符(,它也会失败substr

  • awk -- 'BEGIN{exit !(ARGV[1] == ARGV[2])}' "$a" "$b": 如果$a$b被识别为数字(至少是十进制整数和浮点数,如 1.2、-1.5e-4,忽略前导尾随空格,有些还识别十六进制、八进制或任何识别的任何东西strtod()),则执行数字比较。否则,取决于实现,它要么是字节到字节的字符串比较,要么exprstrcoll()比较,即是否$a$b排序相同。

也可以看看:


¹包括GNU[[的内置kshbashyash,一些但不是所有的ash基壳和zsh,但是请注意,在zsh=cmd是一种特殊的文件名扩展操作者(在相同的上下文中展开为~user是),该膨胀到对应的命令的路径,因此,除非您关闭equals禁用该功能的选项,否则您需要编写它,[ "$a" '==' "$b" ]否则您会收到=找不到命令的错误。同为[ "$string" '=~' "$regexp" ]


Lri*_*Lri 22

这些在 bash 中是等价的:

[[ $x == "$y" ]]
[[ $x = "$y" ]]
[ "$x" == "$y" ]
[ "$x" = "$y" ]
Run Code Online (Sandbox Code Playgroud)

前两个 $x 变量不必被引用。Bash 在 [ 内部执行分词和路径名扩展,但不在 [[ 内部:

$ x='a b'
$ [ -s $x ]
-bash: [: a: binary operator expected
$ [[ -s $x ]]
$ ls
$ [ a = * ]
-bash: [: a: unary operator expected
$ [[ a = * ]]
$ 
Run Code Online (Sandbox Code Playgroud)

[[ $x = "$y" ]]是一个字符串比较但是[[ $x = $y ]]一个模式匹配表达式:

$ y='a*'; [[ aa = "$y" ]]; echo $?
1
$ y='a*'; [[ aa = $y ]]; echo $?
0
Run Code Online (Sandbox Code Playgroud)

-eq 仅用于整数:

$ [[ x.x -eq x.x ]]
-bash: [[: x.x: syntax error: invalid arithmetic operator (error token is ".x")
$ x=9; [[ "x" -eq 9 ]]; echo $?
0
Run Code Online (Sandbox Code Playgroud)

另请参阅BashFAQ/031:测试、[ 和 [[ 之间有什么区别?.


小智 7

=都是==运算符。在某些语言(如 C)中,一种用于为变量赋值,另一种用于比较值(算术表达式的结果)。事实上,这两个运算符正是算术求值中的运算符。A$((a=23))是赋值,a$((a==23))是算术比较。

\n\n
$ echo "$((a=11)) $((a==23))" "$((a=23))" "$((a==23))"\n11 0 23 1\n
Run Code Online (Sandbox Code Playgroud)\n\n

但在测试构造内部(所有test[\xe2\x80\xa6][[\xe2\x80\xa6]])两个运算符的含义相同并执行相同的操作。

\n\n

所以,所有这些选项:

\n\n
test "$a" =  "$b"\n   [ "$a" =  "$b" ]\n  [[ "$a" =  "$b" ]]\ntest "$a" == "$b"\n   [ "$a" == "$b" ]\n  [[ "$a" == "$b" ]]\n
Run Code Online (Sandbox Code Playgroud)\n\n

bash中是等价的于测试二进制相等性(引用的变量)。如果正确的变量未加引号,则它可能会被解释为模式并进行相应的匹配:作为模式而不是文字字符串。

\n\n

带引号的运算符\\=\\==在 test 和 中使用时也是等效的[\xe2\x80\xa6]。但引用的运算符\\==在内部失败[[\xe2\x80\xa6]]

\n\n

对于其他 shell,结果各不相同(正确的结果应该是Y -(true false),不同于 0 (true) 和 1 (false) 的退出代码将报告为失败)\xc2\xa4。某些 shell 会失败- -(退出代码始终为 1)。

\n\n
                     | dash  ksh   bash  zsh   \n  test a  =  "$b"    | Y -   Y -   Y -   Y -    \n     [ a  =  "$b" ]  | Y -   Y -   Y -   Y -    \n    [[ a  =  "$b" ]] | \xc2\xa4 \xc2\xa4   Y -   Y -   Y -    \n  test a  == "$b"    | \xc2\xa4 \xc2\xa4   Y -   Y -   - -    \n     [ a  == "$b" ]  | \xc2\xa4 \xc2\xa4   Y -   Y -   - -    \n    [[ a  == "$b" ]] | \xc2\xa4 \xc2\xa4   Y -   Y -   Y -    \n  test a \\=  "$b"    | Y -   Y -   Y -   Y -    \n     [ a \\=  "$b" ]  | Y -   Y -   Y -   Y -    \n    [[ a \\=  "$b" ]] | \xc2\xa4 \xc2\xa4   Y -   - -   - -    \n  test a \\== "$b"    | \xc2\xa4 \xc2\xa4   Y -   Y -   Y -    \n     [ a \\== "$b" ]  | \xc2\xa4 \xc2\xa4   Y -   Y -   Y -    \n    [[ a \\== "$b" ]] | \xc2\xa4 \xc2\xa4   Y -   - -   - -\n
Run Code Online (Sandbox Code Playgroud)\n\n

所有选项都可以在 ksh 中使用,带引号的运算符在 bash 和 zsh(在 内部[[\xe2\x80\xa6]])中失败,而未加引号的运算符\\=\\==zsh(在 外部[[\xe2\x80\xa6]])中也失败。

\n