In code samples on the internet and others' shell scripts, you will often find command substitution used with for to iterate over lines of output; this is especially common with commands such as ls, cat, and grep:
# Bad practice
for item in $(ls) ; do
...
done
for line in $(cat TODO.txt) ; do
...
done
for match in `grep username ~/accounts` ; do
...
done
You should never attempt to iterate over lines with for loops, as in the preceding examples. The primary reason for this is that other characters besides newlines can separate arguments – spaces, for example. Another is that in order for the preceding code to work, the command substitution has to be unquoted, meaning that characters such as * or ? in the output can wreak havoc.
There are workarounds for both of these problems that partly work, such as setting the IFS variable and the -f shell option, respectively, but there's no real need for them when while read -r loops work better "out of the box."
If you want to iterate over output from a file or the output of a command, always use a while read -r loop. Limit for to iterate over arguments or arrays, or the C-style for loop described in the next section.