Bash命令组:为什么花括号需要分号?

时间:2014-01-20 23:53:50

标签: bash syntax grouping parentheses braces

我知道grouping commands in 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'
$ 

我正在寻找一些有关为何情况的见解。我不是在寻找诸如之类的答案,因为文档说的是“”,因为它的设计方式是“。我想知道 为什么 这是设计的方式。或者,如果它只是一个历史文物?

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

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

1 个答案:

答案 0 :(得分:22)

由于{}是命令中的第一个单词,因此只会将其识别为特殊语法。


这里有两个重点,这两点都可以在bash手册的definitions section中找到。首先,是元字符列表

  

metacharacter

     
    
      

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

    
  

该列表包括括号但不包括大括号(既不是卷曲也不是方形)。请注意,它不是具有特殊含义的字符的完整列表,但它是分隔标记的完整字符列表。因此{}不会分隔令牌,只有当它们与元字符相邻时才会被视为令牌,例如空格或分号。

虽然大括号不是元字符,但它们由parameter expansion(例如${foo})和brace expansion(例如foo.{c,h})中的shell专门处理。除此之外,它们只是普通人物。例如,命名文件{ab}}{没有问题,因为这些词不符合任一参数扩展的语法(在{{之前需要$ 1}})或括号扩展(在{{之间至少需要一个逗号)。就此而言,您可以使用}{作为文件名,而无需引用符号。同样,您可以调用文件}ifdone,而无需考虑引用该名称。

后面这些代币是“保留字”:

  

time

     
    
      

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

    
  

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

while

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

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

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

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

  

这种识别[作为保留字]只有在没有引用任何字符且该字用作以下字符时才会出现:

     
      
  • 命令的第一个字......
  •   

(识别保留字的地方的完整列表稍长,但上面是一个非常好的总结。)换句话说,保留字只有当它们是命令的第一个字时才被保留< / em>的。并且,由于[time是保留字,因此如果它们是命令中的第一个字,则它们只是特殊语法。

示例:

{

我可以写更多关于shell解析的内容,特别是bash解析,但它会很快变得乏味。 (例如,关于何时}开始评论以及何时只是普通字符的规则。)近似摘要是:“不要在家里试试”;实际上,唯一可以解析shell命令的是shell。并且不要试图理解它:它只是一个随意的任意选择和历史异常的集合,很多但不是全部基于不用新功能打破古代shell脚本的需要。