Bash 命令组:为什么花括号需要分号?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/21246552/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Bash command groups: Why do curly braces require a semicolon?
提问by Digital Trauma
I know the difference in purpose between parentheses ()
and curly braces {}
when grouping commands in bash.
在 bash 中对命令进行分组时,我知道括号()
和大括号之间的用途不同。{}
But why does the curly brace construct require a semicolon after the last command, whereas for the parentheses construct, the semicolon is optional?
但是为什么花括号结构在最后一个命令之后需要一个分号,而对于圆括号结构,分号是可选的?
$ 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' $
I'm looking for some insight as to why this is the case. I'm not looking for answers such as "because the documentation says so"or "because it was designed that way". I'd like to know whyit was designed this is way. Or maybe if it is just a historical artifact?
我正在寻找有关为什么会出现这种情况的一些见解。我不是在寻找诸如“因为文档是这样说的”或“因为它是这样设计的”之类的答案。我想知道为什么它是这样设计的。或者,也许它只是一件历史文物?
This may be observed in at least the following versions of bash:
这至少可以在以下版本的bash 中观察到:
- GNU bash, version 3.00.15(1)-release (x86_64-redhat-linux-gnu)
- GNU bash, version 3.2.48(1)-release (x86_64-apple-darwin12)
- GNU bash, version 4.2.25(1)-release (x86_64-pc-linux-gnu)
- 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)
回答by rici
Because {
and }
are only recognized as special syntax if they are the first word in a command.
因为{
和}
仅当它们是命令中的第一个单词时才被识别为特殊语法。
There are two important points here, both of which are found in the definitions sectionof the bash manual. First, is the list of metacharacters:
这里有两个重点,都可以在bash 手册的定义部分找到。首先,是元字符列表:
metacharacter
A character that, when unquoted, separates words. A metacharacter is a blank or one of the following characters: ‘|', ‘&', ‘;', ‘(', ‘)', ‘<', or ‘>'.
metacharacter
不加引号时用于分隔单词的字符。元字符是空格或以下字符之一:“|”、“&”、“;”、“(”、“)”、“<”或“>”。
That list includes parentheses but not braces (neither curly nor square). Note that it is not a complete list of characters with special meaning to the shell, but it is a complete list of characters which separate tokens. So {
and }
do not separate tokens, and will only be considered tokens themselves if they are adjacent to a metacharacter, such as a space or a semi-colon.
该列表包括括号但不包括大括号(既不是卷曲的也不是方形的)。请注意,它不是对 shell 具有特殊含义的完整字符列表,而是用于分隔标记的完整字符列表。因此{
,}
不要将标记分开,只有当它们与元字符(例如空格或分号)相邻时才会被视为标记本身。
Although braces are not metacharacters, they are treated specially by the shell in parameter expansion(eg. ${foo}
) and brace expansion(eg. foo.{c,h}
). Other than that, they are just normal characters. There is no problem with naming a file {ab}
, for example, or }{
, since those words do not conform to the syntax of either parameter expansion (which requires a $
before the {
) or brace expansion (which requires at least one comma between {
and }
). For that matter, you could use {
or }
as a filename without ever having to quote the symbols. Similarly, you can call a file if
, done
or time
without having to think about quoting the name.
虽然大括号不是元字符,但它们在参数扩展(例如${foo}
)和大括号扩展(例如foo.{c,h}
)中被 shell 特殊处理。除此之外,他们只是普通角色。命名文件没有问题{ab}
,例如, or }{
,因为这些词不符合参数扩展($
在 之前需要一个{
)或大括号扩展(在{
和之间至少需要一个逗号}
)的语法。就此而言,您可以使用{
或}
作为文件名,而无需引用符号。同样,您可以调用 file if
,done
或者time
无需考虑引用名称。
These latter tokens are "reserved words":
这些后面的标记是“保留词”:
reserved word
A word that has a special meaning to the shell. Most reserved words introduce shell flow control constructs, such as
for
andwhile
.
reserved word
一个对壳有特殊意义的词。大多数保留字都引入了 shell 流控制结构,例如
for
和while
。
The bash manual doesn't contain a complete list of reserved words, which is unfortunate, but they certainly include the Posix-designated:
bash 手册不包含保留字的完整列表,这是不幸的,但它们肯定包括 Posix 指定的:
! { }
case do done elif else
esac fi for if in
then until while
as well as the extensions implemented by bash (and some other shells):
以及由 bash(和其他一些 shell)实现的扩展:
[[ ]]
function select time
These words are not the same as built-ins (such as [
), because they are actually part of the shell syntax. The built-ins could be implemented as functions or shell scripts, but reserved words cannot because they change the way that the shell parses the command line.
这些词与内置词(例如[
)不同,因为它们实际上是 shell 语法的一部分。内置函数可以作为函数或 shell 脚本来实现,但保留字不能,因为它们改变了 shell 解析命令行的方式。
There is one very important feature of reserved words, which is not actually highlighted in the bash manual but is made very explicit in Posix(from which the above lists of reserved words were taken, except for time
):
保留字有一个非常重要的特性,它实际上并没有在 bash 手册中突出显示,但在Posix 中非常明确(从上面的保留字列表中获取,除了time
):
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 …
只有在没有引用任何字符并且该词用作:
- 命令的第一个字……
(The full list of places where reserved words is recognized is slightly longer, but the above is a pretty good summary.) In other words, reserved words are only reserved when they are the first word of a command. And, since {
and }
are reserved words, they are only special syntax if they are the first word in a command.
(保留字被识别的地方的完整列表稍长,但以上是一个很好的总结。)换句话说,保留字只有在它们是命令的第一个单词时才被保留。并且,由于{
和}
是保留字,如果它们是命令中的第一个字,它们只是特殊语法。
Example:
例子:
ls } # } is not a reserved word. It is an argument to `ls`
ls;} # } is a reserved word; `ls` has no arguments
There is lots more I could write about shell parsing, and bash parsing in particular, but it would rapidly get tedious. (For example, the rule about when #
starts a comment and when it is just an ordinary character.) The approximate summary is: "don't try this at home"; really, the only thing which can parse shell commands is a shell. And don't try to make sense of it: it's just a random collection of arbitrary choices and historical anomalies, many but not all based on the need to not break ancient shell scripts with new features.
关于 shell 解析,特别是 bash 解析,我还有很多可以写的,但它很快就会变得乏味。(例如,关于什么时候#
开始评论和什么时候只是一个普通字符的规则。)大概的总结是:“不要在家里尝试这个”;实际上,唯一可以解析 shell 命令的东西就是 shell。并且不要试图理解它:它只是任意选择和历史异常的随机集合,许多但并非全部基于不使用新功能破坏古老的 shell 脚本的需要。