UNIX Power Tools

UNIX Power ToolsSearch this book
Previous: 44.16 Handling Command-Line Arguments with a for Loop Chapter 44
Shell Programming for the Uninitiated
Next: 44.18 Standard Command-Line Parsing
 

44.17 Handling Arguments with while and shift

A for loop (44.16) is great if you want to handle all of the command-line arguments to a script, one by one. But, as is often the case, some arguments are options that have their own arguments. For example, in the command grep -f filename, filename is an argument to -f; the option and its argument need to be processed together. One good way to handle this is with a combination of while (44.10), test (44.20), case (44.5), and shift. Here's the basic construct:

while [ $# -gt 0 ]
do
    case "$1" in
        -a) options="$options $1";;
            ...
        -f) options="$options $1"
            argfile="$2"
            shift
            ;;
         *) files="$files $1";;
    esac
    shift
done

The trick is this: shift removes an argument from the script's argument list, shifting all the others over by one ($1 disappears, $2 becomes $1, $3 becomes $2 and so on). To handle an option with its own argument, do another shift. The while loop uses test (44.20) to check that $# - the number of arguments - is greater than zero, and keeps going until this is no longer true, which only happens when they have all been used up.

Meanwhile, all the case has to do is to test $1 against the desired option strings. In the simple example shown above, we simply assume that anything beginning with a minus sign is an option, which we (presumably) want to pass on to some program that is being invoked by the script. So all we do is build up a shell variable that will eventually contain all of the options. It would be quite possible to do anything else instead, perhaps setting other shell variables or executing commands.

We assume that anything without a minus sign is a file. This last case could be written more robustly with a test to be sure the argument is a file. Here's an example of a simple script that uses this construct to pass an option and some files to pr and from there to a program that converts text to PostScript and on to the print spooler:

while [ $# -ne 0 ]
do
   case $1 in
        +*) pages="$1" ;;
         *) if [ -f "$1" ]; then
              files="$files $1"
            else 
              echo "$0: file $1 not found" 1>&2
            fi;;
   esac
   shift
done
pr $pages $files | psprint | lpr

This approach is perhaps obsolete if you have getopts (44.18), since getopts lets you recognize option strings like -abc as being equivalent to -a -b -c but I still find it handy. [In this example, it's essential. The pr option +page-list starts with a plus sign. getopt and getopts don't support those old-style options. -JP ]

- TOR


Previous: 44.16 Handling Command-Line Arguments with a for Loop UNIX Power ToolsNext: 44.18 Standard Command-Line Parsing
44.16 Handling Command-Line Arguments with a for Loop Book Index44.18 Standard Command-Line Parsing

The UNIX CD Bookshelf NavigationThe UNIX CD BookshelfUNIX Power ToolsUNIX in a NutshellLearning the vi Editorsed & awkLearning the Korn ShellLearning the UNIX Operating System