General comment: any new answer which gives a new and useful insight into this question will be rewarded with a bonus.
The Bash reference manual mentions that Bash supports the following for-loop constructs:
for name [ [in [words ...] ] ; ] do commands; done
for (( expr1 ; expr2 ; expr3 )) ; do commands ; done
Surprisingly, the following for-loop constructs are also valid:
for i in 1 2 3; { echo $i; }
for ((i=1;i<=3;++i)); { echo $i; }
These unusual constructs are not documented at all. Neither the Bash manual, the Bash man-pages nor The Linux Documentation Project make any mention of these constructs.
When investigating the language grammar one can see that using
open-and-close braces ({ commands; }
) as an alternative to do commands; done
is a valid construct that is implemented for both
for-loops and select statements and dates back to Bash-1.14.7
[1].
The other two loop-constructs:
until test-commands; do consequent-commands; done
while test-commands; do consequent-commands; done
do not have this alternative form.
Since a lot of shell-languages are related, one can find that these constructs are also defined there and mildly documented. The KSH manual mentions:
For historical reasons, open and close braces may be used instead of
do
anddone
e.g.for i; { echo $i; }
while ZSH implements and documents similar alternatives for the other loop-constructs, but with limitations. It states:
For the
if
,while
anduntil
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.
Question: What is the origin of this construct and why is this not propagated to the other loop-constructs?
Update 1: There are some very useful and educational comments below this post pointing out that this is an undocumented Bourne Shell feature which seems to be the result of a C-vs-sh language battle in the early days.
Update 2: When asking the question: Why is this language feature not documented? to the Gnu Bash mailinglist, I received the following answer from Chet Ramey (current lead-developer of 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.
Related questions/answers:
- A bash loop with braces?
- Hidden features of Bash (this answer)
- [U&L] What is the purpose of the “do” keyword in Bash for loops?
Footnotes: [1] I did not find earlier versions, I do believe it predates this