4

I am trying to run the following script using getopts to parse the options but it does not seem to work:

#!/bin/bash
set -x
echo $@
while getopts "rf" opt
do
  case "${opt}" in
    r)
        ropt=${OPTARG}
        ;;
    f)
        fopt=${OPTARG}
        ;;
  esac
done

shift $((OPTIND -1))

echo $fopt $ropt

The output I get is:

$ ./myscript.sh -f opt2 -r opt1
+ echo -f opt2 -r opt1
-f opt2 -r opt1
+ getopts rf opt
+ case "${opt}" in
+ fopt=
+ getopts rf opt
+ shift 1
+ echo

+ set +x

Do you have any ideas on what am I doing wrong?

Kusalananda
  • 320,670
  • 36
  • 633
  • 936
trikelef
  • 381
  • 1
  • 4
  • 13

1 Answers1

10

You expect your options to take option-arguments, but you don't let getopts know about this.

You should use

while getopts "r:f:" opt; do ...; done

i.e., each option that takes an argument should have : after it in the argument string to getopts.

You'll probably also want a default case branch at the end to handle invalid options:

 *) usage >&2
    exit 1

(the error message (about invalid option or missing option argument) will be displayed by getopts itself, usage is expected to be a function that you will have defined that prints a short help message to standard output).

Also, don't forget to double quote all expansions, even $(( OPTIND - 1 )).

Related to that last point:

Kusalananda
  • 320,670
  • 36
  • 633
  • 936
  • Why double quote `$((OPTIND -1))`? Isn't the result of an arithmetic expression always a number? – user000001 Dec 12 '18 at 17:43
  • 2
    @user000001 Yes, and `$IFS` may include digits. which means that the number could be split into multiple words/numbers. Test with `n=123; ( IFS=13; echo $n )`. – Kusalananda Dec 12 '18 at 17:45
  • Thant's interesting, never thought of that case – user000001 Dec 12 '18 at 17:47
  • @user000001 Very few does. Fortunately, _most_ shells reset `IFS` for each new shell invocation. `dash` does not, so potentially one could `export IFS=0123456789` before running a `/bin/sh` shell script on Unices where `sh` is `dash` just to see in what way it breaks. – Kusalananda Dec 12 '18 at 17:48
  • I more benign example might be someone setting `IFS=-` to split something on dashes, and then not resetting it, causing the leading minus sign to be lost. Arguably the bug would be caused by not resetting the original value of `IFS` and not by the lack of quotes, but I guess it never hurts to program defensively. – user000001 Dec 12 '18 at 18:02