替代 for 循环结构

Alternative for-loop construct

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


Bash reference manual提到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 man-pagesLinux 文档 Project 提及这些结构。

调查 language grammar 时可以看到使用 打开和关闭大括号 ({ 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 manual 提到:

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

for i; { echo $i; } 

而 ZSH 为其他循环构造实现了和 documents 类似的替代方案,但有限制。它指出:

For the if, while and until commands, in both these cases the test part of the loop must also be suitably delimited, such as by [[ ... ]] or (( ... )), else the end of the test will not be recognized.


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


更新 1: 下面有一些非常 and 的评论 这个 post 指出这是一个未记录的 Bourne Shell 功能,这似乎是早期 C-vs-sh 语言斗争的结果。


更新 2: 当问这个问题时:为什么这个语言特性没有记录?Gnu Bash mailinglist,我从 Chet Ramey(GNU bash 的现任首席开发人员)那里收到了以下答复:

It's never been documented. The reason bash supports it (undocumented) is because it was an undocumented Bourne shell feature that we implemented for compatibility. At the time, 30+ years ago, there were scripts that used it. I hope those scripts have gone into the dustbin of history, but who knows how many are using this construct now.

I'm going to leave it undocumented; people should not be using it anyway.


相关questions/answers:


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

[W]hy is this not propagated to the other loop-constructs?

whileuntil 命令的大括号形式在句法上会产生歧义,因为您无法将 [=61 分开=] 来自 consequent-commands,它们之间没有明显的分隔符,因为它们都是 defined by POSIX to be compound lists.

例如,支持此类构造的 shell 可以在下面的命令中选择任何一个大括号组作为 consequent-commands 并且无论哪种方式将是一个合理的选择。

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

由于其模棱两可的形式,该命令可以翻译成以下任一形式;没有一个翻译比另一个更准确,而且它们做的事情完全不同。

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

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

鉴于我们已经对 whileuntil 命令有了一致的语法,我真的看不出 向他们传播这种替代形式。

关于它的起源,见: