Bash命令组:为什么花括号需要分号?
我知道括号Bash命令组:为什么花括号需要分号?,bash,syntax,grouping,parentheses,braces,Bash,Syntax,Grouping,Parentheses,Braces,我知道括号()和大括号{}在使用时的不同 但是为什么花括号构造在最后一个命令后需要分号,而对于圆括号构造,分号是可选的 $ 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
()
和大括号{}
在使用时的不同
但是为什么花括号构造在最后一个命令后需要分号,而对于圆括号构造,分号是可选的
$ 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'
$
$whilefalse;做(回音“你好”回音“再见”);完成
$whilefalse;做(回声“你好”;回声“再见”);完成
$whilefalse;做{echo“你好”;echo“再见”};完成
$whilefalse;做{echo“你好”;echo“再见”};完成
bash:意外标记“完成”附近出现语法错误
$
我想了解一下为什么会这样。我不是在寻找这样的答案,比如“因为文档上这么说”或者“因为它是这样设计的”。我想知道为什么它是这样设计的。或者如果它只是一件历史文物
这至少可以在以下版本中观察到:
- GNUBash,版本3.00.15(1)-发行版(x86_64-redhat-linux-GNU)
- GNUBash,版本3.2.48(1)-发布版(x86_64-apple-darwin12)
- GNUBash,版本4.2.25(1)-发行版(x86_64-pc-linux-GNU)
- 因为
{
和}
只有在它们是命令中的第一个单词时才被识别为特殊语法
这里有两个要点,它们都可以在bash手册的中找到。首先是元字符列表:
元字符
一种字符,在不加引号的情况下分隔单词。元字符是空白字符或以下字符之一:“|”、“&”、“;”、”(“,”)“,”
该列表包括括号,但不包括大括号(既不是卷曲的,也不是方形的)。请注意,它不是对shell具有特殊意义的字符的完整列表,而是分隔标记的字符的完整列表。因此,{
和}
不会分离标记,只有当它们与元字符(如空格或分号)相邻时,才会将其视为标记本身
尽管大括号不是元字符,但它们在(例如${foo}
)和(例如foo.{c,h}
)中被shell特别处理。除此之外,他们只是普通的角色。例如,命名文件{ab}
,或}{
,没有问题,因为这些单词不符合参数扩展(在{
之前需要$
)或大括号扩展(在{
和}
之间至少需要一个逗号)的语法。就此而言,您可以使用{
或}
作为文件名,而无需引用符号。类似地,您可以在不考虑引用名称的情况下调用文件(如果)、完成
或时间
)
后面这些标记是“保留字”:
保留字
对shell有特殊意义的词。大多数保留词引入shell流控制结构,如for
和while
bash手册没有包含完整的保留字列表,这是不幸的,但它们肯定包括指定的Posix:
! { }
case do done elif else
esac fi for if in
then until while
以及bash(和其他一些shell)实现的扩展:
这些词与内置词(如[
)不同,因为它们实际上是shell语法的一部分。内置词可以作为函数或shell脚本实现,但保留词不能,因为它们改变了shell解析命令行的方式
保留字有一个非常重要的特性,实际上在bash手册中没有突出显示,但在中非常明确(从中获取了上述保留字列表,除了时间
):
该识别[作为保留字]仅在未引用任何字符且该字用作:
- 命令的第一个字
(识别保留字的位置的完整列表稍长,但上面是一个很好的总结。)换句话说,保留字仅在它们是命令的第一个字时被保留
是保留字,仅当它们是命令中的第一个字时才是特殊语法
例如:
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脚本的需要。为了参考,请注意在编写shell时使用的bash版本可能会有所帮助正在测试。@JonathonReinhart-问题中已经提到了版本-谢谢。那么“因为那是”大括号和圆括号之间的微妙区别已经清楚地描述了。虽然这是一个很好的答案,不值得就此结束,但请注意,SO的范围仅限于实际的、可回答的问题。如果一个问题本质上是历史性的,它不会改变你参与开发实践的方式。它们显然是特殊的l正如OP所发现的,也许你可以进一步说明它们为什么特别,以及“如果它们是命令中的第一个单词”的意义是什么?@Kev,一如既往,因为设计者决定这样做。事实上,它允许你编写echo{}
并获得{}
已打印。@rici+1用于精确和简洁。值得注意的是,{
和}
被定义为保留字,而不是像(
和)
@digitaltrampion:好了
ls } # } is not a reserved word. It is an argument to `ls`
ls;} # } is a reserved word; `ls` has no arguments