Because the POSIX grammar allows it.
The format for the for loop is as follows:
for name [ in [word ... ]]
do
compound-list
done
First, the list of words following in shall be expanded to generate a list of items. Then, the variable name shall be set to each item, in turn, and the compound-list executed each time. If no items result from the expansion, the compound-list shall not be executed. Omitting:
in word...
shall be equivalent to:
in "$@"
The formal grammar for the for
loop looks like
for_clause : For name do_group
| For name sequential_sep do_group
| For name linebreak in sequential_sep do_group
| For name linebreak in wordlist sequential_sep do_group
For
is a grammar token for the string for
. sequential_sep
is either ;
or one or several newlines and linebreak
is a single optional newline. The do_group
at the end is your do ...; done
.
This means that the valid for
loops are
Loop over "$@"
:
for name do ...; done
Loop over "$@"
:
for name; do ...; done
Loop over empty list:
for name in; do ...; done
Loop over non-empty list:
for name in word-list; do ...; done
The third form is valid but doesn't do anything. It exists to allow loops whose word-list expands to nothing.
set
within the script, the loop without the list will not loop over the arguments of the script, but over the new positional parameters. – Kusalananda Dec 02 '18 at 09:02