#!/bin/bash -e
ARGUMENT_LIST=(
"arg-one"
"arg-two"
"arg-three"
)
# read arguments
opts=$(getopt \
--longoptions "$(printf "%s:," "${ARGUMENT_LIST[@]}")" \
--name "$(basename "$0")" \
--options "" \
-- "$@"
)
eval set --$opts
while [[ $# -gt 0 ]]; do
case "$1" in
--arg-one)
argOne=$2
shift 2
;;
--arg-two)
argTwo=$2
shift 2
;;
--arg-three)
argThree=$2
shift 2
;;
*)
break
;;
esac
done
Note
The eval
in eval set --$opts
is required as arguments returned by getopt
are quoted.
$ ./getopt.sh --arg-one "apple" --arg-two "orange" --arg-three "banana"
Even though this works (to some extent, keep reading):
it looks really weird and confusing. It works because
getopt
output starts with a space. But in readers eyes it looks like you callset
with some double-dashed option namely--$opts
. For the sake of clarity it must be written asAnother story is
$opts
must be quoted above. I see it in the commits history first you usedset --$opts
but later you prefixed it witheval
. It surely is right, because otherwise any option value containing a space would split into parts. It could be the end of the story, but this is exactly the time when more spaces matter:As you see, if unquoted, the value undergoes word-splitting and sequences of chars from
$IFS
are replaces with a single space in the printed args.There is one more problem with it being called a 'usage example': it makes a false impression
getopt
doesnt fail. It should be at least this:You might say
-e
bash option hidden in the shebang would silently kill the script on errors, but it is not a good idea for two reasons:/usr/bin/env bash
. Because of SC2096 you cant make it both compatible and with-e
option to bash.