26

一般评论:任何对这个问题提供新的和有用的见解的新答案都将获得奖励。


Bash 参考手册提到 Bash 支持以下 for 循环结构:

for name [ [in [words ...] ] ; ] do commands; done
for (( expr1 ; expr2 ; expr3 )) ; do commands ; done

令人惊讶的是,以下 for 循环结构也是有效的:

for i in 1 2 3; { echo $i; }
for ((i=1;i<=3;++i)); { echo $i; }

这些不寻常的构造根本没有记录。Bash 手册Bash 手册页Linux 文档项目都没有提及这些结构。

在研究语言语法时,可以看到使用开闭大括号 ( { commands; }) 作为替代方案do commands; done是一种有效的构造,它适用于 for 循环和 select 语句,并且可以追溯到Bash-1.14.7 [1]

另外两个循环结构:

until test-commands; do consequent-commands; done
while test-commands; do consequent-commands; done

没有这种替代形式。


由于许多 shell 语言是相关的,人们可以发现这些结构也在那里定义并温和地记录在案。KSH 手册提到:

由于历史原因,可以使用开括号和闭括号代替doand,done例如

for i; { echo $i; } 

而 ZSH 为其他循环结构实现并记录了类似的替代方案,但有局限性。它指出:

对于if,whileuntil命令,在这两种情况下,循环的测试部分也必须适当分隔,例如用 [[ ... ]]or (( ... )),否则将无法识别测试的结束。


问题:这个构造的起源是什么,为什么它没有传播到其他循环构造?


更新 1:在这篇文章下面有一些非常有用和有教育意义的评论指出这是一个未记录的 Bourne Shell 功能,这似乎是早期 C-vs-sh 语言战斗的结果。


更新 2:问问题时:为什么没有记录此语言功能?Gnu Bash 邮件列表中,我收到了 Chet Ramey(GNU bash 的现任首席开发人员)的以下答复:

它从未被记录在案。bash 支持它的原因(未记录)是因为它是一个未记录的 Bourne shell 功能,我们为了兼容性而实现了它。当时,30 多年前,有使用它的脚本。我希望那些脚本已经进入历史的垃圾箱,但谁知道现在有多少人在使用这个结构。

我将不记录它;人们无论如何都不应该使用它。


相关问题/答案:


脚注: [1]我没有找到更早的版本,我相信它早于这个

4

1 回答 1

16

[W] 为什么这不传播到其他循环结构?

whileuntil命令的花括号形式在语法上会产生歧义,因为您无法将test-commandsconsequent-commands分开,因为它们之间没有独特的分隔符,因为它们都由 POSIX 定义复合列表

例如,支持此类结构的 shell 可以选择以下命令中的任一大括号组作为后续命令,无论哪种方式都是合理的选择。

while true; { false; }; { break; }

由于其形式不明确,该命令可以翻译为以下任何一种;两者都不是比另一个更准确的翻译,而且他们做的事情完全不同。

while true; do
    false
done
break
while true; { false; }; do
    break
done

for命令不受这种歧义的影响,因为它的第一部分——一个变量名可选地后跟一个in和一个单词列表,或者((复合命令的一种特殊形式——可以很容易地与构成它的第二部分的大括号组区分开来。

鉴于我们已经为whileuntil命令提供了一致的语法,我真的认为将这种替代形式传播给它们没有任何意义。

Wrt它的起源,见:

于 2020-08-05T08:16:19.247 回答