I think the behavior you want is a bad idea; there exist programs that take options with optional arguments, and they work nothing like what you describe. Your approach will likely confuse your users; it will make it difficult for other programs to interoperate with it; and it will limit the future extensibility of your script. (Imagine you want to add another option later on. your_script.sh -d -e
will pass -e
as an argument to -d
, even if the user wanted to use -d
with no argument and intended -e
as a separate option.) And it's especially bizarre to expect one argument if it's on the command line, but two arguments from standard input.
That said . . .
To achieve some of the effect of an optional option-argument, you can tell getopts
to be "silent" (that is, to use "silent error reporting") by putting a colon :
at the beginning of the option string. (For example, instead of getopts d: ...
, you would write getopts :d: ...
.) Then, when an option's argument is missing, it will set the option-name to :
(instead of d
) and OPTARG
to the option-name (namely d
, instead of the option-argument).
For example, the below script can be called either as script.sh -d foo
or as script.sh -d
, with the latter causing the user to be prompted to type a value:
#!/bin/bash
if getopts :d: arg ; then
if [[ "$arg" == d ]] ; then
d="$OPTARG"
else
read -p 'Enter d: ' d
fi
echo "d is: $d"
else
echo 'no d'
fi
Resulting in:
$ ./script.sh
no d
$ ./script.sh -d
Enter d: x
d is: x
$ ./script.sh -d y
d is: y