为什么没有“;” 在 sh 循环中“做”之后?

kei*_*ley 30 shell

为什么写在一行上时;do在 shell 循环之后没有一个字符?

这就是我的意思。当写在多行上时,for循环看起来像:

$ for i in $(jot 2)
> do
>     echo $i
> done
Run Code Online (Sandbox Code Playgroud)

在一行上:

$ for i in $(jot 2); do echo $i; done
Run Code Online (Sandbox Code Playgroud)

除了该行之外,所有折叠的行;后面都有一个do,如果包含;,则是一个错误。可能比我聪明得多的人认为这是正确的做法是有原因的,但我不知道原因是什么。这对我来说似乎不一致。

用相同的while循环了。

$ while something
> do
>     anotherthing
> done
$ while something; do anotherthing; done
Run Code Online (Sandbox Code Playgroud)

jes*_*e_b 32

这就是命令的语法。请参阅复合命令

for name [ [in [words …] ] ; ] do commands; done
Run Code Online (Sandbox Code Playgroud)

特别注意: do commands

大多数人将docommands放在单独的行上以方便阅读,但没有必要,您可以编写:

for i in thing
do something
done
Run Code Online (Sandbox Code Playgroud)

我知道这个问题是专门关于 shell 的,我已经链接到 bash 手册。它在 shell 手册中没有这样写,但在Stephen Bourne为字节杂志一篇文章中是这样写的

斯蒂芬 说:

命令列表是由一个新行或分离或终止一个或多个简单命令的序列;(分号)。此外,像dodone 这样的保留字通常前面有一个换行符或;... 每次执行do 之后的命令列表时依次执行。

  • 同样有趣的是为什么 ** 不能** 是分号,例如 `for i in thing; 做; 某物; 完成`。尽管允许换行,但不允许使用分号。 (6认同)

ilk*_*chu 13

我不知道这种语法的最初原因是什么,但让我们考虑这样一个事实,即while循环可以在条件部分采用多个命令,例如

while a=$(somecmd);
      [ -n "$a" ];
do
    echo "$a"
done
Run Code Online (Sandbox Code Playgroud)

这里,do关键字是区分条件部分和循环主体所必需的。do是一个像while, ifand then(and done)这样的关键字,它似乎与其他关键字一致,它后面不需要分号或换行符,而是直接出现在命令之前。

替代方案(泛化为ifand while)看起来有些难看,我们需要编写例如

if; [ -n "$a" ]; then
    some command here
fi
Run Code Online (Sandbox Code Playgroud)

for循环的语法是相似的。


Kaz*_*Kaz 11

Shell 语法是基于前缀的。它具有由特殊关键字引入的子句。某些条款必须放在一起。

一个while循环由一个或多个测试命令组成:

test ; test ; test ; ...
Run Code Online (Sandbox Code Playgroud)

并通过一个或多个正文命令:

body ; body ; body ; ...
Run Code Online (Sandbox Code Playgroud)

有些东西必须告诉 shell 一个 while 循环开始了。这就是这个while词的目的:

while test ; test ; test ; ...
Run Code Online (Sandbox Code Playgroud)

但接下来,事情就变得模棱两可了。哪个命令是正文的开始?有些东西必须表明这一点,这就是do前缀的作用:

do body ; body ; body ; ...
Run Code Online (Sandbox Code Playgroud)

最后,必须有一些东西表明最后的尸体已经被看到;一个特殊的关键字可以 done做到这一点。

这些 shell 关键字不需要分号分隔,即使在同一行也是如此。例如,如果您关闭多个嵌套循环,您可以只使用done done done ....

相反,... test ; body ... 如果它们在同一行,则分号介于两者之间。该分号被理解为一个终止符:它属于test. 因此,如果do在它们之间插入关键字,则必须在分号和 之间body。如果它在分号的另一边,它会错误地嵌入到test命令的语法中,而不是放在命令之间。

shell 语法最初由 Stephen Bourne 设计,并受到Algol 的启发。Bourne 非常喜欢 Algol,他在 shell 源代码中使用了大量 C 宏,使 C 看起来像 Algol。您可以从 Version 7 Unix 浏览 1979 年的 shell 源代码。宏在 中mac.h,并且到处都在使用它们。例如,if语句呈现为IF... ELSE... ELIF... FI


mur*_*uru 7

我认为这do在这里并不是特别特别。您收到错误,因为;无法启动命令列表。如果是这样,第一个命令将为空,并且语法不允许空命令(变量赋值或没有命令的重定向,是的,但绝对没有,否)。在任何需要命令列表的地方,这都是正确的:

$ while true; do ; echo foo; done
dash: 1: Syntax error: ";" unexpected
$ while ; true; do; echo; done
dash: 1: Syntax error: ";" unexpected
$ { ; echo foo; }
dash: 1: Syntax error: ";" unexpected
$ if ; true; then echo foo; fi
dash: 1: Syntax error: ";" unexpected
Run Code Online (Sandbox Code Playgroud)

甚至:

$ ; ;
dash: 1: Syntax error: ";" unexpected
Run Code Online (Sandbox Code Playgroud)

在所有这些地方,都需要一个命令列表,所以一个前导;是意外的。