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
  • 333,661
trikelef
  • 411

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
  • 333,661
  • 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