Most shell scripts need to handle command-line arguments - options, filenames,
and so on.
Articles
44.15
,
44.16
,
and
44.17
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
.
[6]
Your Bourne shell may have a built-in command named
getopts
.
constraints.[7]
getopts
lets you deal with multiple complex options without these
To find out whether your shell has
getopts
,
see your on-line
sh
or
getopts
(1) manual page.
getopt
|
If your shell doesn't have
getopts
, you can use the command named
getopt
on the CD-ROM.
getopts
works differently from
getopt
; we won't cover it here. |
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
"$@"
(
44.15
)
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 non-option 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 non-zero
status (
44.7
)
.
Your script can use a loop to parse the
getopt
output.
Here's an example script named
opttest
that shows how
getopt
works.
||
{
:
|
#!/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 (
9.16
)
-
and using the
set
(
44.19
)
command to replace the command-line arguments with the
getopt
output.
The first argument to
set
,
-
(two dashes) (
44.19
)
,
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]
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).