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


我只是想知道究竟是什么区别

[[ $STRING != foo ]]

[ $STRING != foo ]

除了后者是posix兼容的,在sh中发现,前者是在bash中发现的扩展。


344
2017-08-09 21:11




stackoverflow.com/questions/13542832 - Ciro Santilli 新疆改造中心 六四事件 法轮功
如果您还想知道根本不使用括号,例如在一个。的背景下 if 声明,见 mywiki.wooledge.org/BashPitfalls#if_.5Bgrep_foo_myfile.5D - Kev
另外,来自Ubuntu的文档: wiki.ubuntu.com/... - radistao


答案:


有几个不同之处。在我看来,一些最重要的是:

  1. [ 是一个内置于Bash和许多其他现代贝壳。内置的 [ 类似于 test 需要关闭的额外要求 ]。内置的 [ 和 test 模仿功能 /bin/[ 和 /bin/test 以及它们的限制,以便脚本向后兼容。原始可执行文件仍然主要用于POSIX兼容性和向后兼容性。运行命令 type [ 在Bash中表明了这一点 [ 默认情况下被解释为内置。 (注意: which [ 只查找可执行文件 路径 并相当于 type -p [
  2. [[ 不是那么兼容,它不一定适用于任何事情 /bin/sh 指着。所以 [[ 是更现代的Bash / Zsh / Ksh选项。
  3. 因为 [[ 内置于shell中并且没有遗留的要求,您不必担心基于的分词 IFS 变量来搞乱评估带空格的字符串的变量。因此,您实际上不需要将变量放在双引号中。

在大多数情况下,其余部分只是一些更好的语法。要查看更多差异,我建议将此链接指向常见问题答案: test,[和[[?。事实上,如果你认真对待bash脚本,我建议你阅读整篇文章 维基,包括FAQ, 陷阱和指南。 指南部分的测试部分 解释了这些差异,以及作者思考的原因 [[ 如果您不需要担心便携性,那么这是一个更好的选择。主要原因是:

  1. 您不必担心引用测试的左侧,以便它实际上被读取为变量。
  2. 你不必逃避小于和大于 < > 使用反斜杠,以便它们不被评估为输入重定向,这可能通过覆盖文件真的搞砸了一些东西。这又回到了 [[ 是一个内置的。如果[(test)是一个外部程序,那么shell必须以它的计算方式做出异常 < 和 > 除非 /bin/test 正在被召唤,这真的没有意义。

261
2017-08-09 21:56



谢谢,bash常见问题解答的链接是我正在寻找的(不知道该页面,谢谢)。 - 0x89
我用这些信息编辑了你的帖子,但[和测试作为内置函数执行。内置设计用于替换/ bin / [和/ bin / test,但也需要重现二进制文件的限制。命令'type ['验证是否使用了内置函数。 '[只搜索PATH上的可执行文件,相当于'type -P [' - klynch


简而言之:

[是一个bash 内建

[[]]是bash 关键词

关键词: 关键字非常类似于builtins,但主要区别在于特殊的解析规则适用于它们。例如,[是一个bash内置,而[[是一个bash关键字。它们都用于测试内容,但由于[[是一个关键字而不是内置函数,它受益于一些特殊的解析规则,这使得它更容易:

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

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

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


108
2017-12-29 19:42



[ 是一个POSIX shell命令;它不需要内置。 ] 只是该命令查找的参数,因此语法是平衡的。该命令是其同义词 test 除了那个 test 不寻找结束 ]。 - Kaz
看这里: pubs.opengroup.org/onlinepubs/009695399/utilities/test.html - Kaz


行为差异

在Bash 4.3.11中测试过:

  • POSIX vs Bash扩展:

  • 常规命令vs魔法

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

      ] 只是一个论点 [ 这可以防止使用更多的参数。

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

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

      特别是, < 是重定向, && 和 || 连接多个命令, ( ) 除非转义,否则生成子shell \和单词扩展一如既往地发生。

    • [[ 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推荐
  • 分词

    • x='a b'; [[ $x = 'a b' ]]:是的,不需要报价
    • x='a b'; [ $x = 'a b' ]:语法错误,扩展为 [ a b = 'a b' ]
    • x='a b'; [ "$x" = 'a b' ]:相当于
  • =

    • [[ ab = a? ]]:是的,因为它确实如此 模式匹配 (* ? [ 是神奇的)。不会将glob扩展为当前目录中的文件。
    • [ ab = a? ]a? glob扩展。因此可能是真或假,具体取决于当前目录中的文件。
    • [ ab = a\? ]:false,不是glob扩展
    • = 和 == 两者都是一样的 [ 和 [[但是 == 是一个Bash扩展。
    • printf 'ab' | grep -Eq 'a.':POSIX ERE等价物
    • [[ ab =~ 'ab?' ]]:假,失去魔力 ''
    • [[ ab? =~ 'ab?' ]]:是的
  • =~

    • [[ ab =~ ab? ]]:true,POSIX 扩展正则表达式 比赛, ? 没有全局扩展
    • [ a =~ a ]:语法错误
    • printf 'ab' | grep -Eq 'ab?':POSIX等价物

建议

我更喜欢永远使用 []

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

如果你使用 [[ ]] 您:

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

61
2017-07-12 10:22



如何使用 printf 'ab' | grep -Eq 'ab?' 内 if [ … ]? - meeDamian
@meeDamian if ( printf 'ab' | grep -Eq 'a' ); then echo 'a'; fi。 [] 是一个命令就像 grep。该 () 可能不需要该命令我不确定:我添加它是因为 |,取决于Bash如何解析事物。如果没有 | 我相信你可以写 if cmd arg arg; then。 - Ciro Santilli 新疆改造中心 六四事件 法轮功
@meeDamian是的,没必要 () 它似乎: stackoverflow.com/questions/8965509/... - Ciro Santilli 新疆改造中心 六四事件 法轮功
好清单!也可以看看: wiki.ubuntu.com/... - radistao


基于对联机帮助页的相关部分的快速阅读,主要区别似乎是 == 和 != 运算符匹配模式,而不是文字字符串,并且还有 =~ 正则表达式比较运算符。


4
2017-08-09 21:17





单支架 即 [] 是POSIX shell兼容包含条件表达式。

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

在bash中,我们使用数字比较 eqnelt 和 gt,我们可以使用双括号进行比较 ==!=<, 和 > 从字面上。

  • [ 是test命令的同义词。即使它内置于shell中,它也会创建一个新进程。
  • [[ 是一个新的改进版本,它是一个关键字,而不是一个程序。

例如:

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

3
2018-02-08 03:15