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


426

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

[[ $STRING != foo ]]

[ $STRING != foo ]

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


1
如果您还想知道根本不使用方括号,例如在if声明的上下文中,请参见mywiki.wooledge.org/BashPitfalls#if_.5Bgrep_foo_myfile.5D
Kev

同样,来自Ubuntu的文档:wiki.ubuntu.com/…–
radistao

Answers:


309

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

  1. [是Bash和许多其他现代shell中的内置函数。内置[函数类似于test关闭的附加要求]。在内建[test模仿的功能/bin/[,并/bin/test与他们一起的局限性,使脚本会向后兼容。最初的可执行文件仍然存在,主要是为了满足POSIX和向后兼容。type [在Bash中运行命令表示[默认情况下将其解释为内置命令。(注意:which [仅在PATH上查找可执行文件,等效于type -p [
  2. [[不那么兼容,它不一定适用于任何/bin/sh指向的地方。所以[[是更现代的Bash /岩组/ KSH选项。
  3. 因为[[是内置在shell中的,并且没有旧的要求,所以您不必担心基于IFS变量的单词拆分,从而使评估为带空格的字符串的变量变得混乱。因此,您实际上不需要将变量放在双引号中。

在大多数情况下,其余只是一些更好的语法。要查看更多差异,我建议将此链接链接至常见问题解答:test,[和[[有什么区别?。实际上,如果您认真对待bash脚本,建议您阅读整个Wiki,包括FAQ,Pitfalls和Guide。 指南部分的测试部分也解释了这些差异,以及为什么在[[您不必担心便携性时作者认为更好的选择。主要原因是:

  1. 您不必担心引用测试的左侧,以便实际上将其读取为变量。
  2. 您不必< >使用反斜杠将其转义为小于和大于,以免它们被评估为输入重定向,这实际上可能会由于覆盖文件而使某些内容混乱。这又回到[[了内置函数。如果[(test)是一个外部程序,则外壳程序必须在其评估方式上<并且>仅在/bin/test被调用时才例外,这实际上没有任何意义。

5
谢谢,指向bash常见问题解答的链接正是我想要的(不知道该页面,谢谢)。
0x89

2
我使用此信息编辑了您的帖子,但是[和测试是作为内置函数执行的。内建函数旨在替换/ bin / [和/ bin / test,但也需要重现二进制文件的限制。命令'type ['验证是否使用了内置函数。'哪['仅搜索PATH上的可执行文件,并且等效于'type -P ['
klynch

133

简而言之:

[是内置的bash

[[]]是bash 关键字

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

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

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

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


3
[是POSIX shell命令;它 ]仅是该命令要查找的参数,因此语法是平衡的。该命令是的同义词,test除了test不查找结束符]
卡兹(Kaz)


81

行为差异

Bash 4.3.11的一些区别:

  • POSIX vs Bash扩展:

  • 常规命令与魔术

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

      ]只是其中的一个论点而[无法使用进一步的论点。

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

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

      特别<是重定向,&&||连接多个命令,( )除非通过进行转义\,否则将生成子外壳,并且单词扩展将照常进行。

    • [[ X ]]是一个X可以神奇地解析的单一构造。<&&||()经特殊处理,以及分词规则是不同的。

      还有进一步的差异,例如==~

      在Bashese中:[是一个内置命令,并且[[是一个关键字:https : //askubuntu.com/questions/445749/whats-the-difference-between-shell-builtin-and-shell-keyword

  • <

  • &&||

    • [[ a = a && b = b ]]:真实,逻辑
    • [ 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 ) ]:语法错误,()被解释为子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? ]]:是的,因为它确实进行模式匹配* ? [很神奇)。不会将glob扩展到当前目录中的文件。
    • [ ab = a? ]a?glob扩展。根据当前目录中的文件,可能是true还是false。
    • [ ab = a\? ]:错误,不是全局扩展
    • ===在双方的同[[[,不过==是一个bash扩展。
    • case ab in (a?) echo match; esac:POSIX等效
    • [[ ab =~ 'ab?' ]]:错误4,失去魔法''
    • [[ ab? =~ 'ab?' ]]:真
  • =~

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

建议:经常使用[]

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

如果您使用[[ ]]

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

¹源自[[...]]Korn外壳中的等效构造

²,但对于aor的某些值b(例如+index)失败,并且如果ab看起来像十进制整数,则进行数字比较。expr "x$a" '<' "x$b"都可以解决。

³也失败了的一些值ab喜欢!(

在bash 3.2及更高版本中为4,并且未提供与bash 3.1的兼容性(与一样BASH_COMPAT=3.1

5,尽管分组(此处使用{...;}命令组而不是(...)运行不必要的子shell)不是必需的,因为||and &&壳运算符(与||and && [[...]]运算符或-o/ -a [运算符相对)具有相同的优先级。因此[ a = a ] || [ a = b ] && [ a = b ]将是等效的。


如何使用printf 'ab' | grep -Eq 'ab?'范围内if [ … ]
meeDamian '16

1
@meeDamian if ( printf 'ab' | grep -Eq 'a' ); then echo 'a'; fi[]是一样的命令grep。该()可能不需要对命令我不知道:我添加这因为|,取决于猛砸如何解析的事情。如果没有,|我相信你可以写if cmd arg arg; then
Ciro Santilli新疆改造中心法轮功六四事件


1
不错的清单!另请参阅:wiki.ubuntu.com/…–
radistao

5

单个括号,[]POSIX shell兼容以包含条件表达式。

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

在bash中,为我们使用数值比较eqneltgt,用双括号进行比较,我们可以使用==!=<,>字面。

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

例如:

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

4

基于对手册页相关部分的快速阅读,主要的区别似乎是==and !=运算符与模式而不是文字字符串匹配,并且还有=~regex比较运算符。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.