for <NAME>; do <LIST> done
for <NAME> in <WORDS>; do <LIST> done
For every word in <WORDS>, one iteration of the loop is performed and the variable <NAME> is set to the current word. If no "in <WORDS>" is present to give an own word-list, then the positional parameters ("$@") are used (the arguments to the script or function). In this case (and only in this case), the semicolon between the variable name and the do is optional.
If you use the loop-variable inside the for-loop and it can contain spaces, you need to quote it, since normal word-splitting procedures apply.
Like all loops (both for-loops, while and until), this loop can be
break command, optionally as break N to break N levels of nested loopscontinue command, optionally as continue N analog to break N
The return status is the one of the last command executed in <LIST> or 0 (TRUE), if the item list <WORDS> evaluates to nothing (i.e.: "is empty"!).
You can use this function to test how arguments to a command will be interpreted and parsed, and finally used:
argtest() {
n=1
for arg; do
echo "Argument $((n++)): \"$arg\""
done
}
Since pathname expansion will expand all filenames to separate words, regardless of spaces, you can use the for-loop to iterate through filenames in a directory:
for fn in *; do
if [ -h "$fn" ]; then
echo -n "Symlink: "
elif [ -d "$fn" ]; then
echo -n "Dir: "
elif [ -f "$fn" ]; then
echo -n "File: "
else
echo -n "Unknown: "
fi
echo "$fn"
done
Stupid example, I know To be complete: You can change the internal field separator (IFS) to a newline and thus make a for-loop iterating over lines instead of words:
IFS=$'\n' for f in $(ls); do echo $f done
This is just an example. In general
ls(1) outputread command) is a better joice to iterate over lines
It's of course possible to use another for-loop as <LIST>. Here, counting from 0 to 99 in a weird way:
for x in 0 1 2 3 4 5 6 7 8 9; do
for y in 0 1 2 3 4 5 6 7 8 9; do
echo $x$y
done
done
Discussion