Sometimes you want a script that will step through the command-line arguments one by one. (The "$@" parameter (Section 35.20) gives you all of them at once.) The Bourne shell for loop can do this. The for loop looks like this:
for arg in list do ...handle $arg... done
If you omit the in list, the loop steps through the command-line arguments. It puts the first command-line argument in arg (or whatever else you choose to call the shell variable (Section 35.9)), then executes the commands from do to done. Then it puts the next command-line argument in arg, does the loop, and so on, ending the loop after handling all the arguments.
For an example of a for loop, let's hack on the zmore (Section 35.17) script.
case Section 35.11
#!/bin/sh # zmore - Uncompress file(s), display with "more" # Usage: zmore [more options] file [...files] stat=1 # Default exit status; reset to 0 before normal exit temp=/tmp/zmore$$ trap 'rm -f $temp; exit $stat' 0 trap 'echo "`basename $0`: Ouch! Quitting early..." 1>&2' 1 2 15 files= switches= for arg do case "$arg" in -*) switches="$switches $arg" ;; *) files="$files $arg" ;; esac done case "$files" in "") echo "Usage: `basename $0` [more options] file [files]" 1>&2 ;; *) for file in $files do zcat "$file" | more $switches done stat=0 ;; esac
We added a for loop to get and check each command-line argument. For example, let's say that a user typed the following:
% zmore -s afile ../bfile
The first pass through the for loop, $arg is -s. Because the argument starts with a minus sign (-), the case treats it as an option. Now the switches variable is replaced by its previous contents (an empty string), a space, and -s. Control goes to the esac and the loop repeats with the next argument.
The next argument, afile, doesn't look like an option. So now the files variable will contain a space and afile.
The loop starts over once more with ../bfile in $arg. Again, this looks like a file, so now $files has afile ../bfile. Because ../bfile was the last argument, the loop ends; $switches has the options and $files has all the other arguments.
Next, we added another for loop. This one has the word in followed by $files, so the loop steps through the contents of $files. The loop runs zcat on each file, piping it to more with any switches you gave.
Note that $switches isn't quoted (Section 27.12). This way, if $switches is empty, the shell won't pass an empty argument to more. Also, if $switches has more than one switch, the shell will break the switches into separate arguments at the spaces and pass them individually to more.
You can use a for loop with any space-separated (actually, IFS (Section 36.23)-separated) list of words -- not just filenames. You don't have to use a shell variable as the list; you can use command substitution (Section 28.14) (backquotes) or shell wildcards (Section 33.2), or just "hardcode" the list of words:
lpr Section 45.2
for person in Joe Leslie Edie Allan do echo "Dear $person," | cat - form_letter | lpr done
The getopt and getopts (Section 35.24) commands handle command-line arguments in a more standard way than for loops.
-- JP
Copyright © 2003 O'Reilly & Associates. All rights reserved.