关于if语句:在bash中,双方括号[]比单方括号[]更可取吗?

Is double square brackets [[ ]] preferable over single square brackets [ ] in Bash?

一位同事最近在一次代码审查中声称,在类似于

1
2
3
if ["`id -nu`" ="$someuser" ] ; then
     echo"I love you madly, $someuser"
fi

他无法提供一个理由。有吗?


[[的惊喜更少,使用起来更安全。但它不是可移植的——posix没有指定它要做什么,只有一些shell支持它(除了bash,我听说ksh也支持它)。例如,您可以

1
[[ -e $b ]]

测试文件是否存在。但是对于[,你必须引用$b,因为它分裂了论点,并且扩展了像"a*"这样的东西([[从字面上理解)。这也与[如何成为一个外部程序以及如何像其他程序一样正常地接收它的参数有关(尽管它也可以是一个内置程序,但它仍然没有这种特殊的处理方式)。

[[还具有其他一些不错的特性,比如与=~匹配的正则表达式以及类似于C语言的运算符。这是一个很好的页面:测试[[[有什么区别?BASH试验


行为差异好的。

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个

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


[[ ]]有更多的特性—我建议您查看高级bash脚本指南以了解更多信息,特别是第7章中的扩展测试命令部分。测验。

顺便说一下,正如指南所指出的,ESH88(1988年版的Korn Shell)中引入了[[ ]]


从哪个比较器,测试,支架,或双支架,是最快的?(http://bashcurescancer.com)

The double bracket is a"compound
command" where as test and the single
bracket are shell built-ins (and in
actuality are the same command). Thus,
the single bracket and double bracket
execute different code.

The test and single bracket are the
most portable as they exist as
separate and external commands.
However, if your using any remotely
modern version of BASH, the double
bracket is supported.


不能使用[[的典型情况是在autotools configure.ac脚本中,括号有一个特殊的和不同的含义,因此您必须使用test,而不是[或[--请注意,test和[是同一个程序]。


[[]]双括号在特定版本的sunos下不可移植,在函数声明中完全不可移植,方法是:gnu bash,版本2.02.0(1)-发布(sparc-sun-solaris2.6)


简言之,[]更好,因为它不分叉另一个过程。没有括号或单个括号比双括号慢,因为它分叉另一个进程。