The bash manual specifies the syntax for a compound for statement like
for name [ [ in [ word ... ] ] ; ] do list ; done
which means that the semicolon before do is optional if the in clause is omitted. [Note 2].
However, the Posix specification only lists the following three works for for_clause :
for_clause : For name linebreak do_group | For name linebreak in sequential_sep do_group | For name linebreak in wordlist sequential_sep do_group ;
For reference, linebreak is possibly an empty NEWLINE sequence, and sequential_sep is a semicolon or NEWLINE , possibly followed by a NEWLINE sequence:
newline_list : NEWLINE | newline_list NEWLINE ; linebreak : newline_list | /* empty */ ; separator : separator_op linebreak | newline_list ; sequential_sep : ';' linebreak | newline_list ;
As far as I can see, this forbids the syntax for foo; do :; done for foo; do :; done for foo; do :; done .
In practice, all the shells I tried (bash, dash, ksh, and zsh) accept as for foo; do :; done for foo; do :; done for foo; do :; done , so for foo do :; done for foo do :; done without complaint, regardless of Posix or their own documentation [Note 3].
Is this a random omission in the Posix standard grammar, or should the semicolon be used in this syntax as a common extension to the standard?
Adding
In the XCU for loop description, Posix seems to insist on newline characters:
The format for the loop for is as follows:
for name [ in [ word * ... ]] do compound-list done
However, in the volume of the Justification it is clear that the grammar is for the last word:
The format is shown with great use of <newline> characters. See Grammar in the XCU Shell Charter for an exact description of where <newline> and <semicolon> characters can be used interchangeably.
Notes
Apparently this is the first SO question, which is a pair of shell and language-lawyer , No idle-curiosity , which may have been more appropriate.
The bash manual is not quite clear about newlines; what he says:
In most cases, the list in the command description can be separated from the rest of the command by one or more newline characters, and a newline may follow the semicolon.
This makes it clear that the semicolon preceding done can be replaced with a new line, but it does not seem to mention that the same conversion can be performed at the semicolon preceding do .
Both ksh and zsh seem to insist that after name there is a semicolon or a new line, although implementations do not insist on it.
The ksh man page shows the syntax:
for vname [ in word ... ] ;do list ;done
(I believe that the semicolon in ;do and ;done represents βa semicolon or a new line.β I cannot find any specific instruction for this effect, but this is the only way to understand the syntax description.)
The zsh manual shows:
for name ... [ in word ... ] term do list done
where term is at least one newline or ; .