关于if语句:Bash中单方括号和双方括号之间的区别

Difference between single and double square brackets in Bash

我正在阅读有关if的bash示例,但有些示例是用单方括号编写的:

1
2
3
4
if [ -f $param ]
then
  #...
fi

其他双方括号:

1
2
3
4
if [[ $? -ne 0 ]]
then
    start looking for errors in yourlog
fi

有什么区别?


单个[]是posix shell兼容的条件测试。

[[]]是标准[]的扩展,由bash和其他shell(如zsh、ksh)支持。它们支持额外的操作(以及标准的POSIX操作)。例如:||代替-o,regex与=~匹配。在关于条件构造的bash手册部分中可以找到更完整的差异列表。

只要您希望脚本可以跨shell进行移植,就可以使用[]。如果希望[]不支持条件表达式并且不需要可移植,请使用[[]]


行为差异好的。

在bash 4.3.11中测试:好的。

  • posix与bash扩展:好的。

    • [是posix
    • [[是一个bash扩展1,文档如下:https://www.gnu.org/software/bash/manual/bash.html conditional constructions
  • 常规命令vs魔法好的。

    • [只是一个有着奇怪名字的常规命令。好的。

      ]只是[的一个论点,它阻止了进一步的论点的使用。好的。

      Ubuntu16.04实际上在coreutils提供的/usr/bin/[上有一个可执行文件,但是bash内置版本优先。好的。

      bash解析命令的方式没有任何改变。好的。

      具体来说,<是重定向,&&||连接多个命令,( )生成子代码,除非由\转义,并且字扩展照常发生。好的。

    • [[ X ]]是一个使X能够被神奇地解析的单一构造。对<&&||()进行了特殊处理,分词规则不同。好的。

      还有其他的区别,如==~。好的。

      在bashese中:[是内置命令,[[是关键字:https://askubuntu.com/questions/445749/whats-the-difference-between-shell-built in-and-shell-keyword好的。

  • <好的。

    • [[ a < b ]]:辞书编纂比较
    • [ a \< b ]:同上。\是必需的,或者像其他命令一样进行重定向。BASH扩展。
    • expr a \< b > /dev/null:posix equivalent2,参见:如何在bash中测试词法小于或等于的字符串?
  • &&||。好的。

    • [[ a = a && b = b ]]:真、逻辑和
    • [ a = a && b = b ]:语法错误,&&被解析为与命令分隔符cmd1 && cmd2
    • [ a = a -a b = b ]:等效,但被posix3否决
    • [ a = a ] && [ b = b ]:posix和可靠的等价物
  • (好的。

    • [[ (a = a || a = b) && a = b ]]:假
    • [ ( a = a ) ]:语法错误,()被解释为子shell
    • [ \( a = a -o a = b \) -a a = b ]相当,但posix不赞成()
    • { [ a = a ] || [ a = b ]; } && [ a = b ]posix等价物5
  • 扩展后的分词和文件名生成(split+glob)好的。

    • x='a b'; [[ $x = 'a b' ]]对,不需要报价
    • x='a b'; [ $x = 'a b' ]:语法错误,扩展到[ a b = 'a b' ]
    • x='*'; [ $x = 'a b' ]:当前目录中有多个文件时出现语法错误。
    • x='a b'; ["$x" = 'a b' ]:posix等价物
  • =好的。

    • [[ ab = a? ]]:是的,因为它进行模式匹配(* ? [是魔法)。不全局扩展到当前目录中的文件。
    • [ ab = a? ]a?全球扩张。因此,根据当前目录中的文件,可能为真或假。
    • [ ab = a\? ]错误,不是全局扩展
    • ===[[[中是相同的,但==是bash扩展。
    • case ab in (a?) echo match; esac:posix等价物
    • 以东十一〔58〕假,与以东十一〔59〕失去魔力。
    • [[ ab? =~ 'ab?' ]]
  • =~好的。

    • [[ ab =~ ab? ]]为真,posix扩展正则表达式匹配,?不全局扩展
    • [ a =~ a ]:语法错误。没有等价的bash。
    • printf 'ab
      ' | grep -Eq 'ab?'
      :POSIX等效(仅限单线数据)
    • awk 'BEGIN{exit !(ARGV[1] ~ ARGV[2])}' ab 'ab?':posix等价物。

建议:务必使用[]。好的。

我见过的每个[[ ]]构造都有posix等价物。好的。

如果您使用[[ ]]您:好的。

  • 失去可移植性
  • 强迫读者学习另一个bash扩展的复杂性。[只是一个有着奇怪名字的常规命令,不涉及特殊的语义。

1灵感来源于Korn Shell中等效的[[...]]结构。好的。

2.但是对于ab的某些值(如+index失败,如果ab看起来像十进制整数,则进行数值比较。expr"x$a" '<'"x$b"在这两个方面都起作用。好的。

3.对于ab的某些值,如!(也失败。好的。

在bash 3.2及更高版本中为4,且未启用与bash 3.1的兼容性(与BASH_COMPAT=3.1类似)好的。

5.尽管分组(这里使用{...;}命令组而不是(...)命令组,因为||&&shell运算符(而不是||&&[[...]]运算符或-o-a[运算符)是不必要的。e同等优先级。因此,[ a = a ] || [ a = b ] && [ a = b ]将是等效的。好的。好啊。


用于状态测试的单个支架内(即])一些运算符(如single =由所有shell支持,而某些较旧的shell不支持使用运算符==

用于状态测试的双括号内(即]])在新旧外壳中使用===没有区别。

编辑:我还应该注意:在bash中,总是使用双括号[……]]如果可能的话,因为它比单个支架更安全。我将通过以下示例说明原因:

1
if [ $var =="hello" ]; then

如果$var恰好为空,那么脚本将看到:

1
if [ =="hello" ]; then

这会破坏你的剧本。解决方案是使用双括号,或者总是记住在变量周围加引号("$var")。双括号是更好的防御性编码实践。


[[是一个bash关键字,类似于(但比)[命令。

http://mywiki.wooledge.org/bashfaq/031和http://mywiki.wooledge.org/bashguide/testsandconditionals

除非你是为posix sh写的,否则我们推荐[[


bash手册上说:

When used with [[, the ‘<’ and ‘>’ operators sort lexicographically
using the current locale. The test command uses ASCII
ordering.

(TEST命令与[]相同)


您可以使用双方括号进行light regex匹配,例如:

if [[ $1 =~"foo.*bar" ]] ; then

(只要您使用的bash版本支持此语法)