为什么没有“;” sh 循环中的“do”之后?

为什么没有“;” sh 循环中的“do”之后?

为什么在一行中写入 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

答案1

这就是该命令的语法。看复合命令

for name [ [in [words …] ] ; ] do commands; done

特别注意: do commands

大多数人将docommands放在单独的行上以方便阅读,但这不是必需的,您可以编写:

for i in thing
do something
done

我知道这个问题是专门关于 shell 的,我已经链接到 bash 手册。 shell 手册中没有这样写,但在 shell 中却是这样写的斯蒂芬·伯恩撰写的文章对于字节杂志。

斯蒂芬 说:

A命令列表;是由换行符或(分号)分隔或终止的一系列一个或多个简单命令。此外,保留字如完毕通常前面有换行符或;...依次每次命令列表如下被执行。

答案2

while我不知道这种语法的原始原因是什么,但让我们考虑一下循环可以在条件部分接受多个命令的事实,例如

while a=$(somecmd);
      [ -n "$a" ];
do
    echo "$a"
done

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

另一种选择(推广到ifwhile)看起来有点难看,我们需要写例如

if; [ -n "$a" ]; then
    some command here
fi

循环的语法for非常相似。

答案3

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

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

test ; test ; test ; ...

以及通过一个或多个身体命令:

body ; body ; body ; ...

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

while test ; test ; test ; ...

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

do body ; body ; body ; ...

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

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

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

shell 语法最初由 Stephen Bourne 设计,灵感来自大陵五。 Bourne 非常喜欢 Algol,以至于他在 shell 源代码中使用了大量 C 宏,使 C 看起来像 Algol。你可以浏览 Unix 版本 7 中 1979 年的 shell 源代码。宏位于 中mac.h,并且它们到处都在使用。例如语句if呈现为IF………… ELSEELIFFI

答案4

简短的回答,因为这是由POSIX shell 语法do和之间的任何内容都done被视为一组语句,而 while;是顺序分隔符:

for_clause       : For name                                      do_group
                 | For name                       sequential_sep do_group
                 | For name linebreak in          sequential_sep do_group
                 | For name linebreak in wordlist sequential_sep do_group

do_group         : Do compound_list Done 

sequential_sep   : ';' linebreak
                 | newline_list

此外,如果;有必要,标准将明确说明这一点,并将包括sequential_sepafter Do

相关内容