Shell syntax is prefix based. It has clauses introduced by special keywords. Certain clauses have to go together.
A while
loop is made out one or more testing commands:
test ; test ; test ; ...
and by one or more body commands:
body ; body ; body ; ...
Something has to tell the shell that a while loop begins. That's the purpose of the while
word:
while test ; test ; test ; ...
But then, things are ambiguous. Which command is the start of the body? Something has to indicate that, and that's what the do
prefix does:
do body ; body ; body ; ...
and, finally, something has to indicate that the last body has been seen; a special keyword done
does that.
These shell keywords don't require semicolon separation, even on the same line. For instance, if you close several nested loops, you can just have done done done ...
.
Rather, the semicolon is between ... test ; body ...
if they are on the same line. That semicolon is understood to be a terminator: it belongs with the test
. Therefore, if a do
keyword is inserted between them, it has to go between the semicolon and body
. If it were on the other side of the semicolon, it would be wrongly embedded inside the test
command's syntax, rather than placed between commands.
The shell syntax was originally designed by Stephen Bourne, and is inspired by Algol. Bourne loved Algol so much that he used lots of C macros in the shell source code to make C look like Algol. You can browse the 1979-dated shell sources from Version 7 Unix. The macros are in mac.h
, and they are used all over the place. For instance if
statements are rendered as IF
... ELSE
... ELIF
... FI
.
while
/for
either.