zsh`getopts` OPTIND行为与其他shellbash,sh不一致

问题描述

在POSIX shell,bash中$OPTIND的定义非常一致和直观-这是下一个要读取的arg的索引。但是,它在zsh中的行为令人费解,我找不到它的文档。

示例:

# ./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

现在执行:

>>> 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
.

这已在zsh 5.3.1 (amd64-portbld-freebsd11.0)

上进行了测试

解决方法

您应该不太在意OPTIND的值。

重要的是在处理完所有选项之后的下一个参数:

对于bash和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

在使用local OPTIND的任何函数中始终包含getopts 否则,所有getopts共享一个全局OPTIND