Most shell scripts need to handle
command-line arguments — options, filenames, and so on. Section 35.20, Section 35.21, and Section 35.22 show how to parse command
lines with any Bourne shell. Those methods have two problems. You can't combine
arguments with a single dash, e.g., -abc
instead of -a -b -c
. You also can't specify
arguments to options without a space in between, e.g., -b
arg
in addition to -b
arg
.[7]
Your Bourne shell may have a built-in command named getopts.[8] getopts lets you deal with multiple complex options without these constraints. To find out whether your shell has getopts, see your online sh or getopts(1) manual page.
getopt takes two or more arguments. The first is a string that can contain letters and colons (:). Each letter names a valid option; if a letter is followed by a colon, the option requires an argument. The second and following arguments are the original command-line options; you'll usually give "$@" (Section 35.20) to pass all the arguments to getopt.
getopt picks each option off the command
line, checks to see if the option is valid, and writes the correct option to its
standard output. If an option has an argument, getopt writes the argument after its option. When getopt finds the first nonoption argument (the
first argument that doesn't start with a -
character), it outputs two dashes (--
) and
the rest of the arguments. If getopt finds an
invalid option, or an option that should have an argument but doesn't, it prints
an error message and returns a nonzero status
(Section
35.12).
Go to http://examples.oreilly.com/upt3 for more information on: opttest
Your script can use a loop to parse the getopt output. Here's an example script named opttest that shows how getopt works:
||
Section 35.14, :
Section 36.6
#!/bin/sh set -- `getopt "ab:" "$@"` || { echo "Usage: `basename $0` [-a] [-b name] [files]" 1>&2 exit 1 } echo "Before loop, command line has: $*" aflag=0 name=NONE while : do case "$1" in -a) aflag=1 ;; -b) shift; name="$1" ;; --) break ;; esac shift done shift # REMOVE THE TRAILING -- echo "aflag=$aflag / name=$name / Files are $*"
The
script has two legal options. The -a
option sets the variable
named aflag to 1
. The
-b
option takes a single argument; the argument is stored
in the variable named name. Any other arguments are
filenames.
The
script starts by running getopt inside
backquotes (Section 28.14) and using the set (Section
35.25) command to replace the command-line arguments with the
getopt output. The first argument to
set, -- (two
dashes) (Section
35.25), is important: it makes sure that set passes the script's options to getopt instead of treating them as options to the shell itself.
An echo command shows the output of getopt. Then the loop parses the getopt output, setting shell variables as it goes.
When the loop finds the --
argument from
getopt, it quits and leaves the remaining filenames (if
any) in the command-line arguments. A second echo shows what's in the shell variables and on the command line
after the loop. Here are a few
examples:
%opttest
Before loop, command line has: -- aflag=0 / name=NONE / Files are %opttest -b file1 -a file2 file3
Before loop, command line has: -b file1 -a -- file2 file3 aflag=1 / name=file1 / Files are file2 file3 %opttest -q -b file1
getopt: illegal option -- q Usage: opttest [-a] [-b name] [files] %opttest -bfile1
Before loop, command line has: -b file1 -- aflag=0 / name=file1 / Files are %opttest -ab
getopt: option requires an argument -- b Usage: opttest [-a] [-b name] [files]
Some
old Bourne shells have problems with an empty "$@"
parameter (Section
37.5). If the opttest script doesn't
work with an empty command line, as in the first example above, you can change
the "$@"
in the script to ${1+"$@"}
. If you find you're still having some
trouble running the script, particularly with bash, try setting the GETOPT_COMPATIBLE
environment variable, which sets GNU getopt
to emulate the older, less featureful version. Also be sure to read the GNU
getopt(1) manual page, as it details the support for
POSIX-style long options (which let you do things like pass --
longoptions
to programs such as GNU getopt.)
The advantages of getopt are that it minimizes extra code necessary to process options and fully supports the standard Unix option syntax (as specified in intro of the User's Manual).
—JP and BR
[7] Although most Unix commands allow this, it is actually contrary to the Command Syntax Standard Rules in intro of the User's Manual. Check your shell's manual pages for whether it supports getopts.
[8] Both bash and ksh have it. getopts replaces the old command getopt; it is better integrated into the shell's syntax and runs more efficiently. C programmers will recognize getopts as very similar to the standard library routine getopt(3).