为什么写在一行上时,shell循环中没有;
字符?do
这就是我的意思。当写在多行上时,for
循环看起来像:
$ for i in $(jot 2)
> do
> echo $i
> done
在一行上:
$ for i in $(jot 2); do echo $i; done
除了该行之外,所有折叠的行都;
在它们之后得到一个,如果你包含,这是一个错误。可能比我聪明得多的人认为这是正确的做法是有原因的,但我不知道原因是什么。对我来说似乎不一致。do
;
while
循环也一样。
$ while something
> do
> anotherthing
> done
$ while something; do anotherthing; done
那是命令的语法。请参阅复合命令
特别注意:
do commands
大多数人将
do
andcommands
放在单独的一行以方便阅读,但这不是必需的,您可以编写:我知道这个问题是专门关于 shell 的,我已经链接到 bash 手册。在 shell 手册中并没有这样写,但在Stephen Bourne为字节杂志撰写的一篇文章中是这样写的。
斯蒂芬 说:
我不知道这种语法的原始原因是什么,但让我们考虑一下
while
循环可以在条件部分中采用多个命令的事实,例如在这里,
do
关键字对于区分循环的条件部分和主体是必要的。do
是一个类似while
,if
和then
(anddone
) 的关键字,它似乎与其他关键字一致,它后面不需要分号或换行符,而是立即出现在命令之前。替代方案(推广到
if
andwhile
)看起来有些难看,我们需要写例如循环的语法
for
是相似的。Shell 语法是基于前缀的。它具有由特殊关键字引入的子句。某些条款必须放在一起。
while
一个或多个测试命令组成一个循环:并通过一个或多个身体命令:
有些东西必须告诉 shell 一个 while 循环开始了。这就是这个
while
词的目的:但是,事情是模棱两可的。哪个命令是body的开始?有些东西必须表明这一点,这就是
do
前缀的作用:最后,必须有一些东西表明已经看到了最后一具尸体;一个特殊的关键字
done
可以做到这一点。这些 shell 关键字不需要分号分隔,即使在同一行。例如,如果你关闭几个嵌套循环,你可以只拥有
done done done ...
.相反,
... test ; body ...
如果它们在同一行上,则分号位于它们之间。该分号被理解为一个终止符:它属于test
. 因此,如果do
在它们之间插入关键字,则必须在分号和body
. 如果它在分号的另一边,它会被错误地嵌入到test
命令的语法中,而不是放在命令之间。shell 语法最初是由 Stephen Bourne 设计的,并受到Algol的启发。Bourne 非常喜欢 Algol,以至于他在 shell 源代码中使用了大量 C 宏来使 C 看起来像 Algol。您可以从版本 7 Unix 浏览 1979 年的 shell 源代码。宏在 中
mac.h
,并且它们在所有地方都被使用。例如if
,语句呈现为IF
...ELSE
...ELIF
...FI
。我认为这
do
在这里并不是特别特别。您收到错误,因为;
无法启动命令列表。如果是这样,第一个命令将为空,并且语法不允许空命令(没有命令的变量分配或重定向,是的,但绝对没有,否)。在任何需要命令列表的地方都是如此:甚至:
在所有这些地方,都需要一个命令列表,因此前导
;
是出乎意料的。语法是:
任何换行符,无论是在命令列表中还是在“do”或“done”之前,都可以用“;”代替。
在“do”之后和“in”之前允许使用换行符(但不是“;”),只是为了让事情看起来更好,但在那里需要换行符是没有意义的。
if
与它的关键字相似:当命令很短时,这是非常可读的:简短的回答,因为这是由POSIX shell grammar指定的。
do
和之间的任何东西done
都被认为是一组语句,;
而是顺序分隔符:此外,如果
;
有必要,标准将明确说明这一点,并将包括sequential_sep
afterDo
。因为 do 是一个关键字,它后面的内容本质上是参数。Bash 解释器知道更多内容。这类似于没有';' 在 for 命令中的 i 之后。实际上,您可以在 i in for 之后添加一个换行符,然后在新行上键入其余部分,它会正常工作。