Not sensibly with Bash's/POSIX getopts, but you could do it with the "enhanced" getopt (without an s) from util-linux or Busybox. (And those only, in particular many "traditional" getopt implementations are broken wrt. whitespace also)
The man page says of getopts:
optstring contains the option characters to be recognized; if a character is followed by a colon, the option is
expected to have an argument, which should be separated from it by white space.
there's no mention of optional option-arguments.
Of course you could have another optional option to give the non-default value. E.g. let -n take no argument and just enable nice things, and let -N <arg> take the argument, enable nice things and set the value.
E.g. something like this:
#!/bin/bash
HAS_NICE_THINGS=0
NICE_THINGS_VALUE=50
while getopts nN: option; do
case "${option}" in
n)
HAS_NICE_THINGS=1
shift;;
N)
HAS_NICE_THINGS=1
NICE_THINGS_VALUE=$OPTARG
shift; shift;;
esac
done
if [ "$HAS_NICE_THINGS" = 1 ]; then
echo "nice things enabled with value $NICE_THINGS_VALUE"
fi
would give
$ bash nice-getotps.sh -n
nice things enabled with value 50
$ bash nice-getopts.sh -N42
nice things enabled with value 42
The util-linux getopt takes optional option-arguments with the double-colon syntax. It's a bit awkward to use, and you need to mess with eval, but done correctly, it seems to work.
Man page:
-o shortopts [...] Each short option character in shortopts may be followed by one colon to indicate it has a required argument, and by two colons to indicate it has an optional argument.
With a script to just print the raw values so we can check it works properly (getopt-optional.sh):
#!/bin/bash
getopt -T
if [ "$?" -ne 4 ]; then
echo "wrong version of 'getopt' installed, exiting..." >&2
exit 1
fi
params="$(getopt -o an:: -- "$@")"
eval set -- "$params"
while [ "$#" -gt 0 ]; do
case "$1" in
-n)
echo "option -n with arg '$2'"
shift 2;;
-a)
echo "option -a"
shift;;
--)
shift
break;;
*)
echo "something else: '$1'"
shift;;
esac
done
echo "remaining arguments ($#):"
printf "<%s> " "$@"
echo
we get
$ bash getopt-optional.sh -n -a
option -n with arg ''
option -a
remaining arguments (0):
<>
$ bash getopt-optional.sh -n'blah blah' -a
-n 'blah blah' -a --
option -n with arg 'blah blah'
option -a
remaining arguments (0):
<>
No argument to -n shows up as an empty argument.
Not that you could pass an explicit empty argument anyway, since the option-argument needs to be within the same command line argument as the option itself, and -n is the same as -n"" after the quotes are removed. That makes optional option-arguments awkward to use in that you need to use -nx, as -n x would be taken as the option -n (without an opt-arg), followed by a regular non-option command line argument x. Which is unlike what would happen if -n took a mandatory option-argument.
More about getopt on this Stackoverflow answer to How do I parse command line arguments in Bash?
Note again that support for optional option-arguments is limited
to those particular implementations of getopt, ones most commonly found on Linux systems. Other implementations of getopt don't even support whitespace in arguments as they rely on word splitting of args=$(getopt...); set -- $args.
The "enhanced" versions of getopt have the -T option to test for support of these enhancements. There's some discussion on the limitations and caveats with getopt here:
getopt, getopts or manual parsing - what to use when I want to support both short and long options?
Also, getopt is not a standard tool like getopts is (not sure if that's exactly because of these limitations and differences).
-ntakes a value, what should happen if the user passes-nwith no value? Should it behave as though-nwere not passed? Should-nresult in one value forNICE_THINGSwhile running without-nshould result in another value? Please edit your question and explain what each scenario is.NICE_THINGS, which would be used with just plain-n(with no value).-ioption. In contrast to e.g. the FreeBSD version where the option-argument is mandatory.