7

Why does this option only work the first time it's used, then ignored every other time? It's like it's being reset when the option is not used.

Here's my function:

testopts() {
    local var="o false"
    while getopts "o" option; do
        case "${option}" in
            o)
                var="o true"
                ;;
        esac
    done
    echo $var
}

When running it, it only returns true when passing the option for the first time.

$ testopts
o false
$ testopts -o
o true
$ testopts -o
o false
Jeff Puckett
  • 37,464
  • 17
  • 118
  • 167

2 Answers2

9

You need to add this line at top of your function:

OPTIND=1

Otherwise successive invocation of the function in shell are not resetting this back since function is being run in the same shell every time.

As per help getopts:

Each time it is invoked, getopts will place the next option in the shell variable $name, initializing name if it does not exist, and the index of the next argument to be processed into the shell variable OPTIND. OPTIND is initialized to 1 each time the shell or a shell script is invoked.

anubhava
  • 761,203
  • 64
  • 569
  • 643
3

Resetting OPTIND to 1 works, but it's even better to declare OPTIND as a local variable whenever getopts is used in a function:

#!/bin/bash

# entry function for option parsing
main() {
  local OPTIND OPTARG opt
  while getopts ':a:b' opt; do case "$opt" in
    (a) echo "option 'a' set with '$OPTARG'" ;;
    (b) echo "option 'b' set" ;;         (*) ;;
  esac; done; shift $((OPTIND - 1))

  echo "rest args: ${@@Q}"
}

main "$@"

See also https://eklitzke.org/using-local-optind-with-bash-getopts

ryenus
  • 15,711
  • 5
  • 56
  • 63