KFL
KFL

Reputation: 17850

zsh `getopts` OPTIND behavior not consistent with other shells (bash, sh)

The definition of $OPTIND in POSIX shell, bash are quite consistent and intuitive - it is the index of the next arg to be read. However, its behavior in zsh is quite puzzling, and I can't find document for it.

Example:

# ./test.sh:
foo() {
    while getopts "1:2:34:" flag; do
        echo flag: $flag
        echo arg: $OPTARG
        echo ind: $OPTIND
    done &&
    echo .
}

foo -1 1 -2 2 -3 3 -4 4

Now execute:

>>> sh ./test.sh
flag: 1
arg: 1
ind: 3
flag: 2
arg: 2
ind: 5
flag: 3
arg:
ind: 6    <<<< EXPECTED - next arg should be $6
.

>>> bash ./test.sh
flag: 1
arg: 1
ind: 3
flag: 2
arg: 2
ind: 5
flag: 3
arg:
ind: 6    <<<< EXPECTED - next arg should be $6
.

>>> zsh ./test.sh 
flag: 1
arg: 1
ind: 3
flag: 2
arg: 2
ind: 5
flag: 3
arg:
ind: 5   <<<<<< NOTICE HERE
.

This is tested on zsh 5.3.1 (amd64-portbld-freebsd11.0)

Upvotes: 3

Views: 905

Answers (1)

Philippe
Philippe

Reputation: 26697

You should not care much about the value of OPTIND.

What's important is the next argument after all the options are processed:

Following structure works the same way for both bash and zsh:

# ./test.sh:
foo() {
    local OPTIND flag
    while getopts "1:2:34:" flag; do
        echo flag: $flag
        echo arg: $OPTARG
        echo ind: $OPTIND
    done 
    shift $(( OPTIND - 1 ))
    echo "Next arg is $1"
}

foo -1 1 -2 2 -3 3 -4 4

Always include local OPTIND in any function that use getopts otherwise all getopts share a single global OPTIND

Upvotes: 2

Related Questions