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



我知道在bash中对命令进行分组时,括号()和大括号{}之间的用途不同。

但是,为什么大括号结构需要在最后一个命令后使用分号,而对于圆括号结构,分号是可选的呢?

$while false;do(echo"你好";echo"再见";);已完成$while false;do(echo"你好";echo"再见");已完成$while false;do{echo"你好";echo"再见";};已完成$while false;do{echo"Hello";echo"Goodbye"};已完成bash:意外标记"done"附近出现语法错误$

我想了解为什么会出现这种情况。我不是在寻找之类的答案,因为文档上写着">",因为它是这样设计的。我想知道为什么它是这样设计的。或者,如果它只是一件历史文物?

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

  • GNU bash,版本3.00.15(1)-发行版(x86_64-redhat-linux-GNU)
  • GNU bash,版本3.2.48(1)-发行版(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中非常明确(从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。不要试图理解它:它只是任意选择和历史异常的随机集合,其中许多但并非全部基于不需要用新功能打破古老的外壳脚本。

相关内容

  • 没有找到相关文章

最新更新