但是为什么大括号结构在最后一个命令之后需要分号,而对于括号构造,分号是可选的?
$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)-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)
这里有两个重要的要点,它们都是在bash手册的definitions section中找到的.首先是元字符列表:
Metacharacter
A character that,when unquoted,separates words. A Metacharacter is a blank or one of the following characters: ‘|’,‘&’,‘;’,‘(’,‘)’,‘<’,or ‘>’.
该列表包括圆括号,但不包括括号(既不是卷曲也不是正方形).请注意,它不是shell的特殊意义的完整的字符列表,但它是分隔标记的字符的完整列表.所以{和}不要分开标记,只有当它们与元字符(如空格或分号)相邻时才会被认为是令牌.
虽然大括号不是元字符,但它们在parameter expansion(例如${foo})和brace expansion(例如,foo.{c,h})中由shell特别处理.除此之外,它们只是普通人物.命名文件{ab}不存在任何问题,例如或{},因为这些单词不符合任一参数扩展的语法(需要在{}之前的$或扩展)(这需要至少一个{和}之间的逗号).对于这一点,您可以使用{或}作为文件名,而无需引用符号.同样,您可以调用文件,如果,完成或时间,而不必考虑引用名称.
这些后缀是“保留字”:
reserved word
A word that has a special meaning to the shell. Most reserved words introduce shell flow control constructs,such as
for
andwhile
.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中是非常明确的(除了时间之外,上面列出了保留字)
This recognition [as a reserved word] shall only occur when none of the characters is quoted and when the word is used as:
- The first word of a command …
(保留字被识别的地方的完整列表稍长一些,但以上是一个非常好的总结.)换句话说,保留字仅在命令的第一个字时被保留.而且,由于{和}是保留字,它们只是特殊的语法,如果它们是命令中的第一个字.
例:
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脚本的.