Argument Parsing in Shell Scripts
So, say you are writing a shell script (sh or bash) that needs to take arguments like so:
./script.sh start
./script.sh -v start
./script.sh -c foo.conf start
./script.sh -vc foo.conf start
This took me a bit of doing. First, I tried getopt but apparently all that does is disambiguate -v from -c. That, and the FreeBSD man page claims to have improved the example by making it completely inscrutable.
Eventually I found a reference that explained how to use getopts, which worked a lot better, but all the examples I could find didn’t tell you how to reset $@.
Eventually, I figured out that that last bit is accomplished with shift.
Here’s example code:
#!/bin/sh
#
conf=default.conf
while getopts c:hv o
do case "$o" in
c) conf="$OPTARG";;
h) echo "Usage: $0 -hv -c <config> [start|stop|restart|status]" && exit 1;;
v) verbose="yes";;
\?) echo "Usage: $0 -hv -c <config> [start|stop|restart|status]" && exit 1;;
esac
done
# Reset $@
shift `echo $OPTIND-1 | bc`
echo "conf: $conf"
echo "command: $1"
Notes:
- The while loop iterates
$othrough$@where it conforms to the getopts configuration. - getopts c:hv indicates that -h and -v are boolean arguments, and -c is followed by a string argument.
- $OPTIND is set at the end of getopt, and indicates how many arguments through $@ it parsed.
- Oh, and the shift operation resets
$@by $OPTIND-1, so that$1ends up pointing at the start command, or whatever. - If you’re programming in ksh, you can just set
$OPTIND-1. But if you’re programming in ksh you are far beyond needing to check my blog for argument parsing.