I've written a script that processes long options using getopts and automatically parses these into a variable of the same name as the argument, providing that it is contained in my argument list:
#
# get options
#
optslist=h,help,lat,lon,temp,rain,pop,cdate,cyyyy,cmm,cdd,ctmin,ctmax,crain,cpop,tmiss,rmiss,nday,nhead,nheadt,nheadr,nheadp,climfile,datafile,
while getopts h-: OPT; do # allow -h and -- "with arg"
# support long options: https://stackoverflow.com/a/28466267/519360
if [ "$OPT" = "-" ]; then # long option: reformulate OPT and OPTARG
OPT="${OPTARG%%=*}" # extract long option name
OPTARG="${OPTARG#"$OPT"}" # extract long option argument (may be empty)
OPTARG="${OPTARG#=}" # if long option argument, remove assigning `=`
fi
found=false
for arg in ${optslist//,/ } ; do
case "$OPT" in
h | help )
usage
exit
;;
${arg} )
declare ${arg}=${OPTARG}
found=true
break
;;
esac
done
if [ $found = false ] ; then
echo bad argument $OPT
usage
exit
fi
done
This works okay, so that if I call the script with --cyyyy=2000 then the variable cyyyy contains 2000. However the script contains a bit of a fudge in that it only works if I include at least one manually specified short option in the getopts call, (in this case "h").
If instead I remove this to only have long arguments like this:
while getopts -: OPT; do
I get the error
line 203: getopts: -:: invalid option
I tried to quote it and other methods, but I can't seem to work out a way to get around this error. I can live with the manual -h option, but was curious to know if there is a solution to this.
When you run getopts -: OPT
in dash (a common /bin/sh), it works fine. Bash, however, is convinced that getopts
is being handed an option in this scenario. I would call that a bug.
You can work around this bash issue with getopts -- -: OPT
or getopts :-: OPT
(which additionally instructs getopts to ignore all errors).
Separately, you could simplify
optslist=h,help,lat,lon,temp,rain,pop,cdate,cyyyy,cmm,cdd,ctmin,ctmax,crain,cpop,tmiss,rmiss,nday,nhead,nheadt,nheadr,nheadp,climfile,datafile,
…
for arg in ${optslist//,/ }; do
into
optslist="h help lat lon temp rain pop cdate cyyyy cmm cdd ctmin ctmax crain cpop tmiss rmiss nday nhead nheadt nheadr nheadp climfile datafile"
…
for arg in $optslist; do