====== Handling Command Line Options (getopts) ======
Most Unix command line utilities we have looked at provide multiple command line options. Some of them, such as [[cs_370_-_file_network_and_version_utilities#archiving_and_compression|tar]] allow you to flexibly combine command line options to modify command behavior in multiple ways at once.
The shell (bash) provides the //getopts// construct that allows you to add flexible command line option handling to shell scripts.
===== The getopts construct =====
Sample script #1 that uses getopts:
#!/bin/bash
# getopts_test1
# This script has 3 command line options, one of which takes an argument.
function usage {
echo "script usage: $(basename $0) [-l] [-m] [-o somevalue]" >&2
exit 1
}
while getopts 'lmo:' OPTION; do
case "$OPTION" in
l)
echo "option l selected"
;;
m)
echo "option m selected"
;;
o)
oarg="$OPTARG"
echo "The o option's argument was $oarg"
;;
?)
usage
;;
esac
done
shift "$(($OPTIND - 1))"
* The //getopts// command is used as the condition of a while loop.
* The string after getopts, 'lmo:', contains the single letter options that the script accepts.
* Here, they are l, m and o.
* 'lmo:' is called an //optstring//.
* Within the loop, in a [[cs_370_-_shell_scripting#the_case_structure | case structure]], define what to do with the options that the script will accept.
* Notice the colon after the last option in 'lmo:'. It is the way we tell getopts that the option o requires an argument.
* When the shell script is running, each parsed option will be stored inside the $OPTION variable, while an argument, when present, will become the value of the $OPTARG variable.
* Each option is managed inside the case statement, with a final ? case that will be matched whenever an invalid option is found. In that case we will just echo the user the correct script usage and exit with an error code.
* When the shell script is running, //getopts// looks for a dash (-) and a letter or a series of letters that follow the -. It parses the letters as command line options.
* Valid ways to call the above script:
./getopts_test1 -l -m
./getopts_test1 -l -m -o 3
./getopts_test1 -lm
./getopts_test1 -lm -o 3
./getopts_test1 -lmo 3
./getopts_test1 -lmo3
./getopts_test1 -o 3 -l -m
./getopts_test1 -o3 -lm
./getopts_test1 -o3 -m
(and more)
* The $OPTIND variable contains the number of command line option arguments that //getopts// parsed.
./getopts_test1 -o 3 -l -m # $OPTIND = 4
./getopts_test1 -o3 -lm # $OPTIND = 4
./getopts_test1 -l -m # $OPTIND = 2
./getopts_test1 -lm # $OPTIND = 2
* shift "$(($OPTIND - 1))"
* The [[cs_370_-_shell_scripting#the_while_structure|shift]] command is a shell built-in command which moves the [[cs_370_-_shell_scripting#special_built-in_script_variables|positional parameters]] of the script down a specified number of positions, discarding the related arguments.
* Running shift "$(($OPTIND - 1))" discards the command line options; this is a standard thing to do in a shell script using //getopts//, when the command line options are no longer needed.
==== Command line options plus additional arguments ====
Sample script #2 that uses getopts:
#!/bin/bash
# getopts_test2:
# This script has 3 command line options and
# takes an additional script argument ($1)
while getopts dmy OPTION
do
case $OPTION in
d) dopt=1;;
m) mopt=1;;
y) yopt=1;;
?) echo "Unrecognized or invalid option"
exit 1;;
esac
done
if [ ! -z $dopt ]; then
day=$(date '+%d')
fi
if [ ! -z $mopt ]; then
mon=$(date '+%b')
fi
if [ ! -z $yopt ]; then
year=$(date '+%Y')
fi
shift $(($OPTIND - 1))
echo "The date is: $day $mon $year"
if [ ! -z $1 ]; then
echo "Welcome, $1."
fi
* To display day, month, year and a "Welcome" message, run the script in one of the following ways:
./getopts_test2 -d -m -y Dave
./getopts_test2 -dmy Dave
* Without doing 'shift $(($OPTIND -1 ))' to discard the command line options, the script would not be able to properly process the additional command line argument ($1).
==== Example: text2png_getopts ====
Test a version of the text2png script that uses getopts for command line options handling: [[https://cssegit.monmouth.edu/jchung/csse370repo/-/blob/main/scripts/text2png_getopts|text2png_getopts]]