Quote:
Originally Posted by unSpawn
There are a few common problems in scripting that are easy avoidable if you keep to simple rules, and one of them is using "for" instead of "while" loops. If you don't want to take it it from me, David The H. or other LQ members well-versed in scripting see http://mywiki.wooledge.org/DontReadLinesWithFor
|
To clarify, now that I've stumbled upon this thread...
A
for loop operates on a series of word tokens, like this:
Code:
for word in word1 word2 word3 word4; do
echo "$word"
done
The wordlist can be generated in whatever way you want. You can add them manually, and/or use
brace expansion, or an array, or even a
command substitution, if you know what you're doing.
The key is to understand that command or simple variable substitutions will always be subject to shell word-splitting before being used. That means you can have either a list of simple words (if you leave the quotes off), or one big single entry, if you quote it. There's no way to split the expansion in one place while keeping it unsplit in another, identical place (e.g. spaces within filenames cannot be distinguished from spaces between them). The link provided above shows how it works.
One of the most common is to use
globbing file matching expansion. This is safe, even if the files have whitespace in them, because globbing expansion doesn't happen until after word-splitting is finished. Globs will always expand into lists of complete filename tokens.
As a final warning, however,
for loops do always have a danger of running into system ARG_MAX limits.
For almost all other uses, when reading from commands and files, you should use a
while+read loop, which allows you to cleanly control how the input is delimited and broken up. Of course a
while loop does have a bit of extra complexity involved to it, particularly when delimiting filenames, but it's something you need to learn if you're ever going to be a competent scripter.
One final, kind of hybrid solution, is to somehow split your input into an
array first. The "
${array[@]}" expansion pattern, when quoted, is perfectly safe for use in a
for loop. The only problem is that it usually takes a
while loop to safely set the array contents in the first place.
The new bash
mapfile built-in can make it much easier in some cases, however, at least if the input is delimited by newlines. You can safely use globbing patterns to set an array of filenames too.