1

I'm trying to see whether I can use getopts for my Bash script. However, I'm not sure what's wrong:

#! /bin/bash

while getopts "a:b" opt ; do
    case $opt in
        a)
            A_OPTION="option a was given argument $OPTARG"
            ;;
        b)
            B_OPTION="option b was found"
            ;;
    esac
done
if [ -n "$A_OPTION" ] ; then echo $A_OPTION ; fi
if [ -n "$B_OPTION" ] ; then echo $B_OPTION ; fi
shift $((OPTIND - 1))
echo "The remaining arguments are: $@"

The output is:

$ ./getopts-test foo goo -a moo -b
The remaining arguments are: foo goo -a moo -b
$ ./getopts-test -a moo -b foo goo
option a was given argument moo
option b was found
The remaining arguments are: foo goo
$ ./getopts-test -a moo foo goo -b
option a was given argument moo
The remaining arguments are: foo goo -b
$ ./getopts-test -b foo goo -a moo
option b was found
The remaining arguments are: foo goo -a moo

Why doesn't the script detect the options in all the cases? Is getopts only useful when the options are all provided upfront and not mixed with other arguments?

2 Answers 2

1

(this is too long to be a comment and too poor to be an answer)

getopt try to detect single letter option with - (minus sign), and option with argument.

It stop when there is no (no more) option (no -b, no -a foo). It doesn't parse the full list.

So answer to second question is yes.

You might whish to write a getopt parser yourself and deal with this question are -foo --bar arguements (e.g. a file, a string) or an option.

for a long time tradition was to put options first, argument later, precisely so you knew when option stop, and if -foo was an actual filename.

0

Based on the manpage, it is expected behavior. getopts supports "options" and "option-arguments".

Guideline 4: all options should be preceded by -. That being said, ./getopts-test foo goo -a moo -b will not work as "foo" is not an option nor an option-argument. Hence, it will stop.

An option-argument is specified by ":". In your definition, a: is an option-argument and it parses -a moo and b is just and option that parses -b in ./getopts-test -a moo -b foo goo. The rest (foo goo) is just remaining.

Guideline 8: all arguments for an option-argument should be presented as one comma-separated. That's why ./getopts-test -a moo foo goo -b just parses -a moo. The correct way is ./getopts-test -a moo,foo,goo -b. (same applies to your last case)

Reference:

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .