Naftuli Kay
Naftuli Kay

Reputation: 91630

Invalid option -- ' ' and '-'

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

Answers (1)

John1024
John1024

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.

Minimal example

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

Related Questions