Trying to read my flag and their arguments,
I came accros a case where passing a flag with an expected argument,
fallowed by another flag instead of the expected argument,
would result in the second flag being interpreted as argument for the first flag.
WWW_ALIAS=0
while getopts ':d:a:w' flag; do
case "${flag}" in
d)
DOMAIN_NAME=${OPTARG}
;;
a)
IFS=',' read -ra DOMAIN_ALIASES <<< "${OPTARG}"
;;
w)
WWW_ALIAS=1
;;
:)
echo "[Error] Argument for option -${OPTARG} was omitted." 1>&2
exit 1
;;
\?)
echo "[Warning] Option ${OPTARG} is not supported and will be ignored." 1>&2
;;
esac
done
if [ -z "${DOMAIN_NAME}" ]; then
echo "[Error] Domain parameter (-d) must be set" 1>&2
exit 1
fi
Thus, running ./script.sh -w -d
will trigger the error message at the end of this code example.
But running ./script.sh -d -w
will instead assign -w
to the DOMAIN_NAME
variable while it shouldn't.
Is there a way to make sure that any flag can't be used as argument for a flag ?
CodePudding user response:
The supported syntax for getopts
is:
- a - option
-a
without value; error on unsupported options - a: - option
-a
with value; error on unsupported options - ab - check for options
-a, -b
; error on unsupported options - :ab - check for options
-a, -b
; silences errors on unsupported options
Since you specified d:
, the argument parser will check for an additional value after the switch -d
. Not specifying one, just like in this command: ./script.sh -w -d
will trigger an error from the argument parser (not your code).
Since you specified w
without a (:
after it), the argument parser will NOT check for an additional value after the switch -w
. Hence you don't see an error for that flag.
When you run with -d -w
, the parser sees only the first switch, which is -d
, and it consumes the next token as the argument, which is the expected outcome.
As there a way to make sure that any flag can't be used as argument for a flag?
Yes, there are a couple of options actually.
Option 1: inside the menu, add a sanity check to allow only reasonable values:
...
case "${flag}" in
d)
if [[ "${OPTARG}" == -* ]]; then
echo "Bad argument!"
exit 1
fi
DOMAIN_NAME=${OPTARG}
;;
...
Option 2: Use eval set -- "$OPTS"
Some don't like this option because eval
is evil
. But it's still an option if you are not afraid of this attack vector.
This command will sort the arguments and will prevent things like this from happening.
Find an example here