The bash manual lists the syntax for the for
compound statement as
for name [ [ in [ word ... ] ] ; ] do list ; done
which implies that the semicolon before do
is optional if the in
clause is omitted. [Note 2].
However, the Posix specification lists only the following three productions 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 a possibly-empty sequence of NEWLINE
while sequential_sep
is either a semicolon or a NEWLINE
, possibly followed by a sequence of NEWLINE
:
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, that prohibits the syntax for foo; do :; done
.
In practice, all the shells I tried (bash, dash, ksh and zsh) accept both for foo; do :; done
and for foo do :; done
without complaint, regardless of Posix or their own documentation [Note 3].
Is this an accidental omission in the grammar in the Posix standard, or should the use of the semicolon in that syntax be considered a (commonly-implemented) extension to the standard?
Addendum
In the XCU description of the for loop
, Posix seems to insist on newlines:
The format for the for loop is as follows:
for name [ in [word ... ]]
do
compound-list
done
However, in the Rationale volume, it is made clear that the grammar is intended to be the last word:
The format is shown with generous usage of <newline> characters. See the grammar in XCU Shell Grammar for a precise description of where <newline> and <semicolon> characters can be interchanged.
Notes
Apparently this is the first SO question which pairs shell and language-lawyer. There is no idle-curiosity, which might have been more appropriate.
The
bash
manual is not entirely explicit about newlines; what it says is:In most cases a list in a command's description may be separated from the rest of the command by one or more newlines, and may be followed by a newline in place of a semicolon.
That makes it clear that the semicolon preceding
done
can be replaced by a newline, but does not seem to mention that the same transformation can be performed on the semicolon precedingdo
.Both
ksh
andzsh
seem to insist that there be either a semicolon or a newline after thename
, although the implementations don't insist on it.The
ksh
manpage lists the syntax as:for vname [ in word ... ] ;do list ;done
(I believe that the semicolon in
;do
and;done
represents "a semicolon or a newline". I can't find any definite statement to that effect but it is the only way to make sense of the syntax description.)The
zsh
manual shows:for name ... [ in word ... ] term do list done
????where term is at least one newline or ;.