[[ $a == z* ]] 和 [ $a == z* ] 有什么区别?

[[ $a == z* ]] 和 [ $a == z* ] 有什么区别?

这两者有什么区别吗。

[[ $a == z* ]]

[ $a == z* ] 

我可以举个例子,说明它们会有不同的输出吗?

此外, 的工作方式[[ ]]与 有何不同[ ]

答案1

[[ … ]]和之间的区别[ … ]主要体现在为什么不带引号的空格参数扩展在双括号“[[”内有效,但在单括号“[”内无效?。至关重要的是,[[ … ]]是特殊的语法,而[是命令的一个看起来很有趣的名称。[[ … ]]对于里面的内容有特殊的语法规则,[ … ]没有。

添加了通配符后,[[ $a == z* ]]计算方式如下:

  1. 解析命令:这是[[ … ]]围绕条件表达式的条件构造$a == z*
  2. 解析条件表达式:这是==二元运算符,操作数为$az*
  3. 将第一个操作数展开为变量的值a
  4. 评估==运算符:测试变量的值是否a与模式匹配z*
  5. 计算条件表达式:其结果是条件运算符的结果。
  6. 现在对命令进行求值,如果条件表达式为真,则其状态为 0,如果条件表达式为假,则其状态为 1。

[ $a == z* ]评估方式如下:

  1. 解析命令:这是[带有通过评估单词$a, ==, z*,形成的参数的命令]
  2. 展开$a为变量的值a
  3. 对命令的参数执行分词和文件名生成。
    • 例如,如果 的值为a6个字符的字符串foo b*(通过eg获得a='foo b*'),当前目录下的文件列表为( bar, baz, qux, zim, zum),则扩展的结果为以下单词列表:[, foo, bar,,,,,, .baz==zim​​zum]
  4. [使用上一步中获取的参数 运行该命令。
    • 对于上面的示例值,该[命令抱怨语法错误并返回状态 2。

注意:在 中[[ $a == z* ]],在步骤 3 中, 的值a不会进行分词和文件名生成,因为它位于需要单个单词的上下文中(条件运算符 的左侧参数==)。在大多数情况下,如果单个单词在该位置有意义,则变量扩展的行为就像在双引号中一样。但是,该规则有一个例外:在 中[[ abc == $a ]],如果 的值a包含通配符,则将abc与通配符模式进行匹配。例如,如果ais的值a*则为[[ abc == $a ]]true (因为通配符*来自带引号的扩展$amatches bc),而值为 false (因为来自带引号的扩展的[[ abc == "$a" ]]普通字符不 match )。在里面,双引号没有什么区别,*$abc[[ … ]]除了字符串匹配运算符的右侧===!==~)。

答案2

[是命令的别名test。 Unix 版本 6 有一个if命令,但版本 7(1979)附带了新的伯恩外壳那有几个编程构造包括 if-then-else-elif-fi 构造,并且 Unix 版本 7 添加了testif该命令执行了旧版本中该命令执行的大部分“测试” 。

[被用作别名test,并且两者都被内置到 Unix System III (1981) 的 shell 中。尽管应该指出的是,一些 Unix 变体[直到很久之后才具有命令(直到 2000 年代初期,一些 BSD 上都sh基于 Almquist shelltest内置函数始终包含在ash的源代码中,但在这些 BSD 上它最初被禁用))。

请注意,testaka[是执行“测试”的命令,该命令没有执行任何赋值操作,因此没有理由消除赋值运算符和相等运算符之间的歧义,因此相等运算符是===仅受最近的一些实现支持[(并且只是 的别名=)。

因为[只不过是一个命令,所以 shell 解析它的方式与任何其他命令相同。

具体来说,在您的示例中,$a,因为它没有被引用,所以会根据通常的单词分割规则被分割成几个单词,并且每个单词都会经历文件名生成(又名通配)以产生可能更多的单词,每个单词都会产生命令的单独参数[

同样,z*将扩展到当前目录中以z.

例如,如果$a是,并且当前目录中b* = xz1z2b1和文件,则该命令将获得 9 个参数:、、、、、、、和。b2[[b1b2=x==z1z2]

[将其参数解析为条件表达式。这 9 个参数加起来不构成有效的条件表达式,因此它可能会返回错误。

[[ ... ]]构造可能是在 1988 年左右由 Korn shell 引入的,如下所示:ksh86a1987年没有,而ksh88从一开始就有。

除了 ksh(所有实现)之外,[[...]]bash(自版本 2.02 起)和 zsh 也支持,但这三个实现都是不同的,并且同一 shell 的每个版本之间也存在差异,尽管这些更改通常是向后兼容的(一个值得注意的例外是 bash 的=~已知在某个版本之后当其行为发生变化时会破坏一些脚本)。[[...]]POSIX、Unix 或 Linux (LSB) 未指定。曾多次考虑将其包含在内,但由于主要 shell 支持的通用功能已被命令[case-in-esac构造所涵盖,因此未包含在内。

整个[[ ... ]]结构构成了一个命令。也就是说,它有一个退出状态(这是它最重要的资产,因为它是评估条件表达式的结果),您可以将其通过管道传输到另一个命令(尽管它没有用),并且通常在任何需要的地方使用它使用任何其他命令(仅在 shell 内部,因为它是 shell 构造),但它不会像普通的简单命令一样被解析。里面的内容被解析了通过外壳作为条件表达式,分词和文件名生成的常用规则应用不同。

[[ ... ]]从一开始就知道==并且相当于=1。 ksh 的一个错误(并且导致混乱和许多错误)是=and==不是一个相等运算符,而是一个模式匹配运算符(尽管匹配方面可以通过引用来禁用,但规则不明确,不同外壳程序有所不同)。

在上面的代码中[[ $a == z* ]],shell 会将其解析为与通常规则类似的规则中的几个标记,将其识别为模式匹配比较,将其视为z*与变量内容匹配的模式a

[[ ... ]]一般来说,搬起石头砸自己的脚比用命令更难[。但有一些规则,比如

  • 总是引用变量
  • 切勿使用-aor-o运算符(使用多个[命令和&&and|| 运营商)

[使用 POSIX shell提高可靠性。

[[...]]在不同的 shell 中支持额外的运算符,例如-nt、 regexp 匹配运算符...但列表和行为因 shell 和版本而异。

因此,除非您知道您的脚本将被解释的 shell 及其最低版本,否则坚持使用标准[命令可能更安全。


1一个例外:[[...]]在版本 中添加到 bash 中2.02。直到2.03更改为止,[[ x = '?' ]]将返回 true,而[[ x == '?' ]]将返回 false。也就是说,=在这些版本中使用运算符时,引用不会阻止模式匹配,但在使用==.

答案3

两者都用于计算表达式,[[ 不适用于 POSIX 较旧的 bo​​urn shell,[[ 还支持模式匹配和正则表达式。例子试试这些

[ $n -eq 0 -a $y -eq 0 ] && echo "Error" || echo "Ok"

[[ $n -eq 0 && $y -eq 0 ]] && echo "Error" || echo "Ok"

相关内容