More about scripts with options
Writing a script with arguments is straightforward - you just
need to examine $1 , $2 , etc. - but what
about options?
An option is an argument that commences with a hyphen.
Suppose you wanted to write a command mycommand
which, if given option -h , would print a 'help'
message rather than executing:
$ mycommand -h
Usage: mycommand [-h]
You could check whether $1 is equal to
'-h' , but if you had several possible options, not
just one, the number of permutations would make this a very messy
programming exercise. If mycommand took option
-a in addition to -h , you would have to
check for:
mycommand -h
mycommand -a
mycommand -ah
mycommand -ha
mycommand -a -h
mycommand -h -a
in addition to any invalid options it might be presented with.
The utility getopts is provided to assist in writing
shells that have options. Consider the instance above - we could
have as the contents of mycommand :
while getopts h OPTIONNAME
do
case $OPTIONNAME in
h) echo 'Usage: mycommand [-h]' ;;
?) echo 'Bad option to mycommand'
exit 1 ;;
esac
done
echo "Arguments were $@"
The action getopts performs is to look at
getopts ' first argument, which should be a list of
letters - representing the valid options allowed by the script -
and possibly colons (see below). It then looks at the next argument
to the script in which it occurs. If the argument to a script is an
option (i.e. preceded by a minus sign), getopts checks
to see whether the option is in the list of valid options. If not,
an error message is displayed. The second argument to
getopts is a variable name, which is set to the option
that getopts has discovered. Options must precede all
other arguments that are not options. Only one option at a time
will be checked, so you need to enclose getopts in a
while loop. Let's see what happens when
mycommand is called:
$ mycommand -h hello
Usage: mycommand [-h]
Arguments were -h hello
$ mycommand -x hello
mycommand: illegal option -- x
Bad option to mycommand
$ mycommand hello there
Arguments were hello there
$ mycommand hello -h
Arguments were hello -h
In the case of mycommand hello -h , the argument
-h is not an option, since it has been preceded by an
argument which is not an option.
Some commands take options that require arguments - such as
lp , whose option -d must be followed by
the name of the destination printer. This is handled in
getopts by using colons.
If an option requires an argument, then a colon should follow
the option name in the list of allowed options to
getopts . When that option is encountered, the value of
its argument will be stored in the system variable
OPTARG . For instance, suppose a script called
mymessage takes one option -m , followed
by a string, and displays that string. With no arguments,
mymessage displays Hello . The string
would be an argument to the -m option. This script
might be coded thus:
MESSAGE=Hello # Variable to store message
if getopts m: OPTIONNAME # If an option found
then
case $OPTIONNAME in # Check which option found
m) MESSAGE=$OPTARG;;
?) exit 1;; # Exit if not -m
esac
fi
echo $MESSAGE # Output the message
The number of the next argument to be processed by
getopts is stored in OPTIND , so that by
using shift you can strip off the options from the
command and leave the rest of the arguments for processing
later.
Worked example
Write a script mymail to call mailx to
send messages. The script should take an optional argument
-s (to specify the subject) and one or more other
arguments to specify the recipients (just like mailx ).
No other options apart from -s should be allowed. If
mymail is called without option -s it
should prompt the user for a subject.
$ mymail -s "Test message"
sam
(message)
$ mymail sam
Subject: Test message
(message)
Solution: Use getopts to process
the command line the script is invoked from:
SUBJECT=""
if getopts s: OPTNAME # Valid option is 's'
then # which takes an argument
case $OPTNAME in
s) SUBJECT="$OPTARG";; # The argument to 's' is
# SUBJECT
?) echo "Usage: $0 [-s subject] users"
exit 1;; # Exit if invalid option
esac
fi
shift $(($OPTIND - 1)) # Remove the options
USERS="$*" # The rest of the line
# is the recipients
if [ -z "$USERS" ] # ... which is compulsory
then echo "Must specify recipients"
exit 1 # Exit if no recipients
fi
while [ -z "$SUBJECT" ] # Loop until subject
do # is not null
printf "Subject (no quotes): "
read SUBJECT
done
mailx -s "$SUBJECT" $USERS"
If you intend to write scripts which require options, then using
getopts is the preferred method.
|