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
$o
through$@
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$1
ends 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.