bash命令组:为什么大括号需要分号?

我知道在bash中对命令进行分组时,括号()和花括号{}之间的区别。

但为什么在最后一个命令之后花括号结构需要分号,而对于括号结构,分号是可选的?

$ while false; do ( echo "Hello"; echo "Goodbye"; ); done
$ while false; do ( echo "Hello"; echo "Goodbye" ); done
$ while false; do { echo "Hello"; echo "Goodbye"; }; done
$ while false; do { echo "Hello"; echo "Goodbye" }; done
bash: syntax error near unexpected token `done'
$ 

我正在寻找一些见解,为什么这是事实。 我不是在寻找诸如“因为文档如此说”或“因为它是按照这种方式设计”的答案。 我想知道为什么它是这样设计的。 或者,如果它只是一个历史神器?

至少在以下版本的bash中可以观察到这一点:

  • GNU bash,3.00.15(1)版 - (x86_64-redhat-linux-gnu)
  • GNU bash,版本3.2.48(1)-release(x86_64-apple-darwin12)
  • GNU bash,版本4.2.25(1) - 发行版(x86_64-pc-linux-gnu)

  • 因为如果它们是命令中的第一个单词, {}只会被识别为特殊的语法。


    这里有两点重要,这两点都可以在bash手册的定义部分找到。 首先是元字符列表:

    metacharacter

    一个字符,当不加引号时,分隔单词。 元字符是空格或以下字符之一:'|','&',';','(',')','<'或'>'。

    该列表包括圆括号,但不包括大括号(既不是卷曲也不是正方形)。 请注意,它并不是一个完整的对shell有特殊含义的字符列表,但是它是分隔标记的完整字符列表。 所以{}不要分开令牌,并且只有当它们与元字符(如空格或分号)相邻时才会被视为令牌。

    尽管花括号不是元字符,但它们在参数扩展(例如。 ${foo} )和大括号扩展(例如foo.{c,h} )中被shell特别处理。 除此之外,它们只是普通的字符。 例如命名文件{ab}没有问题,或者}{ ,因为这些单词不符合任一参数扩展的语法(在{之前需要一个$或括号扩展(至少需要一个{}之间的逗号)。 对于这个问题,你可以使用{}作为文件名,而不必引用符号。 同样,你可以调用文件, ifdonetime不必考虑引用名称。

    后面这些令牌是“保留字”:

    reserved word

    一个对shell有特殊含义的词。 大多数保留字引入了shell流控制结构,例如forwhile

    bash手册没有包含完整的保留字列表,这是不幸的,但它们当然包括Posix指定的:

    !    {    }
    case do   done elif else
    esac fi   for  if   in
    then until while
    

    以及由bash(和其他一些shell)实现的扩展:

    [[   ]]
    function  select time
    

    这些词与内置插件(如[ ))不同,因为它们实际上是shell语法的一部分。 内置函数可以作为函数或shell脚本实现,但保留字不能,因为它们改变了shell解析命令行的方式。

    保留字有一个非常重要的特征,在bash手册中实际上没有突出显示,但是在Posix中非常明确(除了time以外,从上面列出了保留字的列表):

    只有当没有引用任何字符并且将该字用作:时,这种识别[作为保留字]

  • 命令的第一个单词...
  • (保留字被识别的地方的完整列表稍长一些,但以上是一个相当不错的总结。)换句话说,保留字只有在它们是命令的第一个字时才被保留。 而且,既然{}是保留字,它们只是特殊的语法,如果它们是命令中的第一个字。

    例:

    ls }  # } is not a reserved word. It is an argument to `ls`
    ls;}  # } is a reserved word; `ls` has no arguments
    

    我可以写更多关于shell解析的东西,特别是bash解析,但它会很快变得乏味。 (例如,关于何时#开始评论以及何时只是普通字符的规则。)大概的摘要是:“不要在家中尝试此操作”; 真的,唯一可以解析shell命令的是shell。 不要试图理解它:它只是一个任意选择和历史异常的随机集合,很多但不是全部基于不需要使用新功能打破古代shell脚本的需要。

    链接地址: http://www.djcxy.com/p/97061.html

    上一篇: bash command groups: Why do curly braces require a semicolon?

    下一篇: How can I escape curly braces at the end of a regular expression