The option string argument you were passing to getopts
would be acceptable to recent versions of the Korn shell getopts
built-in. (I'm not sure when this was added to ksh
, but it was not in the early versions of ksh93. I am not aware of any version of bash that accepts this form of option specification for its getopts
built-in.) Note that having a : after the short option name specifies that that option takes an option argument. (Also note that the case statement processing your command line arguments does not expect option arguments for the -d
, -h
, and -l
options; so there should not have been a colon following these letters in the first operand to getopts
. And, with ksh
, long option names must be presented using a double leading minus sign (e.g., --list
) while short options are presented using a single leading minus sign (e.g., -l
) and multiple short options (without option-arguments) can be grouped behind a single minus sign (e.g., -dl
).
In general optional option-arguments are a bad idea. However, you can assign an empty string as the value of an option argument and behave appropriately if the assigned option-argument value is the empty string.
If you have a recent version of ksh
, play around with script to see getopts
works with short and long options:
#!/bin/ksh
# Initialize variables:
DEBUG=false
IAm=${0##*/}
RET_HELP=2
help_text="Usage: $IAm -h
$IAm [-dl] [-e server] [-m server] [-u server]
$IAm --help
$IAm [--debug] [--list] [--edit=server] [--mount=server] \\
[--unmount=server]"
mode=""
server_info="No server set"
# Process options:
while getopts "d(debug)e:(edit)h(help)l(list)m:(mount)u:(unmount)": name
do case $name in
(e|edit)server_info="$OPTARG"
mode=edit;;
(l|list)mode=list;;
(m|mount)
server_info="$OPTARG"
mode=mount;;
(h|help)printf "%s\n" "$help_text"
exit $RET_HELP;;
(u|unmount)
server_info="$OPTARG"
mode=unmount;;
(d|debug)DEBUG=true;;
(?) printf "%s\n" "$help_text"
exit $BAD_OPTION;;
esac
done
$DEBUG && set -x
shift OPTIND-1
printf "DEBUG=%s, mode=%s, server_info=%s\n" "$DEBUG" "$mode" "$server_info"
printf "Number of remaining operands: %d\n" $#
while [ $# -gt 0 ]
do printf "\toperand:%s\n" "$1"
shift
done
If you save this code in a file named tester
, make it executable:
chmod +x tester
Then you can see that all of the commands:
./tester -e eserver operand1
./tester -eeserver operand1
./tester --edit eserver -- operand1
./tester --edit=eserver operand
./tester -e eserver -- operand1
./tester --edit eserver operand1
./tester --edit=eserver -- operand
all produce exactly the same output:
DEBUG=false, mode=edit, server_info=eserver
Number of remaining operands: 1
operand:operand1
while the command:
./tester --list
works as expected, but
./tester -list
will not work because with a single minus sign, only short options are allowed and there is no -i
option defined, and produces the diagnostic:
./tester: -i: unknown option
Usage: tester -h
tester [-dl] [-e server] [-m server] [-u server]
tester --help
tester [--debug] [--list] [--edit=server] [--mount=server] \
[--unmount=server]
To see how to specify an empty string an an option argument, try:
./tester -m ""
./tester --mount ""
./tester --mount=
./tester --mount=""
but note that the following will not work:
./tester -m""
./tester --mount""