替代的for循环结构

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 man-pagesBash手册还是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手册提到:

For historical reasons, open and close braces may be used instead of do and done e.g.

for i; { echo $i; } 

ZSH实现并记录了其他循环结构的类似替代方案,但存在一些限制。它指出:

对于ifwhileuntil命令,在这两种情况下,循环的测试部分也必须适当地加以限定,例如使用[[...]]((...)),否则测试的结束将无法被识别。


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


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


更新 2:在向Gnu Bash邮件列表提出问题:“为什么这个语言特性没有被记录?”时,我收到了来自GNU bash的当前首席开发人员Chet Ramey的以下回答:

它从未被记录过。bash支持它(未记录)的原因是,它是我们为了兼容而实现的一种未记录的Bourne shell特性。在30多年前的那个时候,有一些脚本使用了它。我希望那些脚本已经成为历史的尘土,但谁知道现在有多少人在使用这种结构。

我将其保留为未记录的;无论如何,人们都不应该使用它。


相关问题/答案:


脚注:[1] 我并没有找到早期的版本,但我相信这篇文章的创作时间早于此。

1个回答

16
“为什么这不会传播到其他循环结构?”由于whileuntil命令的花括号形式在语法上存在歧义,因为您无法将test-commandsconsequent-commands分开,而没有一个明显的定界符,因为它们都被POSIX定义复合列表。例如,支持这种结构的Shell可以选择以下命令中的任何一个花括号组作为consequent-commands,无论哪种方式都是合理的选择。
while true; { false; }; { break; }

由于其含义模糊,该命令可以翻译为以下任意一种方式;两种翻译都没有更准确的翻译,它们执行的操作完全不同。
while true; do
    false
done
break

while true; { false; }; do
    break
done
for 命令不受此歧义的影响,因为它的第一部分——一个变量名称,后面可以选择跟随 "in" 和一系列单词,或者是 (( 复合命令的特殊形式——可以轻松地与形成其第二部分的大括号组进行区分。
鉴于我们已经有了一致的语法来支持 whileuntil 命令,我实际上并没有看到将这种交替形式传播给它们的任何意义。
关于其起源,参见:

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接