it-swarm.cn

bash中的双方括号和单方括号有什么区别?

我只是想知道两者之间到底有什么区别

[[ $STRING != foo ]]

[ $STRING != foo ]

除了后者是posix兼容的以外,在sh中找到,而前者是在bash中找到的扩展。

451
0x89

有几个区别。我认为最重要的几个是:

  1. [是Bash和许多其他现代shell的内置函数。内置的[test类似,但另外需要关闭]。内建的[test模仿功能/bin/[/bin/test及其限制,因此脚本将向后兼容。最初的可执行文件仍然存在,主要是为了满足POSIX和向后兼容。在Bash中运行命令type [表示默认情况下[被解释为内置函数。 (注意:which [仅在[〜#〜] path [〜#〜]上寻找可执行文件,等效于type -p [
  2. [[不那么兼容,它不一定可以与/bin/sh指向的内容一起使用。因此[[是更现代的Bash/Zsh/Ksh=选项。
  3. 因为[[内置在Shell中并且没有旧的要求,所以您不必担心基于[〜#〜] ifs [〜#〜 ]变量可将计算结果为带空格的字符串弄乱。因此,您实际上不需要将变量放在双引号中。

在大多数情况下,其余只是一些更好的语法。要查看更多差异,我建议将此链接指向FAQ答案: test和[和[[? 之间有什么区别。实际上,如果您是认真的关于bash脚本,我建议阅读整个 wiki ,包括FAQ, 陷阱 和指南。 指南部分的测试部分 解释了这些内容以及它们之间的差异,以及为什么您认为[[是更好的选择,如果您不必担心便携性的话,主要原因是:

  1. 您不必担心引用测试的左侧,以便实际上将其读取为变量。
  2. 您不必使用反斜杠转义小于或大于< >的值,以使它们不被评估为输入重定向,这实际上可能会由于覆盖文件而使某些内容混乱。再次回到[[是内置函数。如果[(test)是一个外部程序,则只有在调用<时,Shell才必须以其评估>/bin/test的方式进行异常处理,而这实际上并不会感。
325
Kyle Brandt

简而言之:

[是bash建筑物

[[]]是bash关键字

关键字:关键字与内置函数很像,但主要区别在于特殊的解析规则适用于它们。例如,[是bash内置函数,而[[是bash关键字。它们都用于测试内容,但是由于[[是关键字而不是内置函数,因此它受益于一些特殊的解析规则,这些规则使其变得更加容易:

  $ [ a < b ]
 -bash: b: No such file or directory
  $ [[ a < b ]]

第一个示例返回错误,因为bash尝试将文件b重定向到命令[a]。第二个示例实际上完成了您期望的操作。字符<不再具有文件重定向运算符的特殊含义。

来源: http://mywiki.wooledge.org/BashGuide/CommandsAndArguments

138
abhiomkar

行为差异

Bash 4.3.11的一些区别:

  • POSIX vs Bash扩展:

  • 常规命令与魔术

    • _[_只是一个具有奇怪名称的常规命令。

      _]_只是_[_的参数,可防止使用其他参数。

      Ubuntu 16.04实际上有一个由coreutils提供的_/usr/bin/[_可执行文件,但是bash内置版本优先。

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

      特别是,_<_是重定向的,_&&_和_||_连接多个命令,_( )_会生成子shell,除非被_\_转义,并且单词扩展照常发生。

    • _[[ X ]]_是单个结构,可神奇地解析X。 _<_,_&&_,_||_和_()_会得到特殊处理,并且分词规则也不同。

      还有其他区别,例如_=_和_=~_。

      在Bashese中:_[_是内置命令,而_[[_是关键字: https://askubuntu.com/questions/445749/whats-the-difference-between-Shell -builtin-and-Shell-keyword

  • _<_

  • _&&_和_||_

    • _[[ a = a && b = b ]]_:true,逻辑
    • _[ a = a && b = b ]_:语法错误,_&&_被解析为AND命令分隔符_cmd1 && cmd2_
    • _[ a = a -a b = b ]_:等效,但已被POSIX³弃用
    • _[ a = a ] && [ b = b ]_:POSIX和可靠的等效项
  • _(_

    • [[ (a = a || a = b) && a = b ]]:否
    • [ ( a = a ) ]:语法错误,_()_被解释为子外壳
    • [ \( 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? ]]_:正确,因为它确实 模式匹配 (_* ? [_很神奇)。不会将glob扩展到当前目录中的文件。
    • _[ ab = a? ]_:_a?_球扩展。根据当前目录中的文件,可能是true还是false。
    • _[ ab = a\? ]_:假,不是全局扩展
    • _=_和_==_在_[_和_[[_中都相同,但是_==_是Bash扩展名。
    • case ab in (a?) echo match; esac:等同于POSIX
    • _[[ ab =~ 'ab?' ]]_:否4,用_''_失去魔法
    • _[[ ab? =~ 'ab?' ]]_:是
  • _=~_

    • _[[ ab =~ ab? ]]_:是,POSIX 扩展正则表达式 匹配,_?_不扩展
    • _[ a =~ a ]_:语法错误。没有bash等效项。
    • _printf 'ab\n' | grep -Eq 'ab?'_:等效于POSIX(仅单行数据)
    • awk 'BEGIN{exit !(ARGV[1] ~ ARGV[2])}' ab 'ab?':POSIX等效项。

推荐:始终使用_[]_。

我见过的每个_[[ ]]_构造都有POSIX等效项。

如果您使用_[[ ]]_,则:

  • 失去便携性
  • 迫使读者学习另一个bash扩展的复杂性。 _[_只是一个具有奇怪名称的常规命令,不涉及任何特殊的语义。

¹源自Korn Shell中等效的_[[...]]_构造

²,但对于ab的某些值失败(如_+_或index),并且如果ab看起来像十进制整数。 _expr "x$a" '<' "x$b"_可以同时解决这两个问题。

³,并且对于ab的某些值也会失败,例如_!_或_(_。

4 在bash 3.2及更高版本中并没有提供对bash 3.1的兼容性(例如_BASH_COMPAT=3.1_)

5 尽管不需要分组(此处使用_{...;}_命令组而不是_(...)_,这会运行不必要的子shell),因为_||_和_&&_ Shell运算符(相对于_||_和_&&_ _[[...]]_运算符或_-o_/_-a_ _[_运算符)具有相同的优先级。所以_[ a = a ] || [ a = b ] && [ a = b ]_将是等效的。

单括号[]符合POSIX Shell的要求,用于封装条件表达式。

双括号[[]]是标准POSIX版本的增强(或扩展)版本,bash和其他shell(zsh,ksh)支持此功能。

在bash中,对于数字比较,我们使用eqneltgt,带有双括号的用于比较的我们可以使用==!=<,>从字面上看。

  • [是测试命令的同义词。即使将其内置到Shell中,它也会创建一个新进程。
  • [[是它的新改进版本,它是关键字,而不是程序。

例如:

[ var1 lt var2] #works
[ var1 < var2] #error: var2 No such file or directory 
[ var1 \< var2] #works with escape
[[ var1 < var2]] #works
6
Premraj

根据对手册页相关部分的快速阅读,主要区别在于==!=运算符与模式匹配,而不是文字字符串,并且还有=~正则表达式比较运算符。

4
womble