34

I was recently looking at some code that confused me because it works and I didn't expect it to. The code reduces to this example

#!/bin/bash
for var;
do
  echo "$var"
done

When run with command line arguments is prints them

$ ./test a b c
a
b
c

It is this, that is (to me) unexpected. Why does this not result in an error because var is undefined ? Is using this considered 'good practice' ?

2 Answers2

34

for loops loop on the positional parameters if no in value1 value2... part is specified in all Bourne-like shells.

That was already the case in the Bourne shell from the late 70s, though in the Bourne shell, you'd need to omit that ; (you can also use for i do (except in some old ash versions where you need a newline before the do)).

See What is the purpose of the "do" keyword in Bash for loops? for more information including more surprising variants.

Doing:

for i
do
  something with "$i"
done

is good practice. It's slightly more portable/reliable than the usually equivalent:

for i in "$@"; do
  something with "$i"
done

for which the Bourne shell, ksh88 have some issues under some conditions (like when $# is 0 in some versions of the Bourne shell (which ${1+"$@"} instead of "$@" can work around) or when $IFS doesn't contain the space character in Bourne and ksh88), or when the nounset option is enabled and $# is 0 in some versions of some shells including bash (again with ${1+"$@"} as a work-around).

24

This is the default behavior, yes. It is documented in the help of the for keyword:

terdon@tpad ~ $ help for
for: for NAME [in WORDS ... ] ; do COMMANDS; done
    Execute commands for each member in a list.

    The `for' loop executes a sequence of commands for each member in a
    list of items.  If `in WORDS ...;' is not present, then `in "$@"' is
    assumed.  For each element in WORDS, NAME is set to that element, and
    the COMMANDS are executed.

    Exit Status:
    Returns the status of the last command executed.

So, when you don't give it a list to iterate over, it will default to iterating over $@, the array of positional parameters (a, b and c in your example).

And this behavior is defined by POSIX so yes, it is considered "good practice" as far as that goes.

terdon
  • 242,166