Reputation: 91630
I'm using getopt
to parse my command line arguments. My script is for starting, stopping, restarting, and getting the status of a daemon. I know I could write an init script, but I need my script to be largely portable on Linux machines.
My script takes one command and a few options. Usage is like this:
activemq start -f
activemq start --foreground
activemq stop -k
activemq stop --kill
activemq restart
activemq start
Here's my parsing logic for my options, ie $2
and onward:
options="${@:$(($1+2))}"
set -- $(getopt -o fk --long foreground,kill -- "$options")
foreground=no
killprocess=no
while [ $# -gt 0 ] ; do
case "$1" in
-f | --foreground)
foreground=yes
shift
;;
-k | --kill)
killprocess=yes
shift
;;
--)
shift
;;
*)
echo "Error: unrecognized option: $1" >&2
usage
;;
esac
done
echo "command=$command, foreground=$foreground, killprocess=$killprocess"
Everything works fine with the following invocation:
activemq restart -fk
However, if I try separating them out into individual arguments, it breaks
$ activemq restart -f -k
getopt: invalid option -- ' '
getopt: invalid option -- '-'
What am I missing here?
Upvotes: 0
Views: 4427
Reputation: 113834
options
needs to be an array. Replace this:
options="${@:$(($1+2))}"
set -- $(getopt -o fk --long foreground,kill -- "$options")
With this:
options=("${@:$(($1+2))}")
set -- $(getopt -o fk --long foreground,kill -- "${options[@]}")
getopt
expects that each option string is a separate argument. By using an array, separate arguments are kept separate.
First, let's set some positional parameters:
$ set restart -- -k -f
Now, let's use bash arrays:
$ options=("${@:$(($1+2))}")
$ printf '>>%s\n' "${options[@]}"
>>--
>>-k
>>-f
The printf
statement demonstrates that each positional parameter remains separate.
Now, try without arrays:
$ options="${@:$(($1+2))}"
$ printf '>>%s\n' "$options"
>>-- -k -f
printf
shows that "$options"
creates a single argument where three were expected.
Upvotes: 3