不同 shell 的 getopts 结果大不相同

Very different getopts results with different shells

我在 shell 脚本中做了一些选项解析,本应在 dashbash 中进行内源处理,但我在 bash 中得到了一些奇怪的结果,所以我将脚本的精华放在:

./getopts :

fn()
{
    local verbose opt
    while getopts "v" opt; do
        case "$opt" in v) verbose=1;; ?) return 1;; esac
    done; shift $((OPTIND - 1))
    echo -n "'$verbose' "
}
fn -v; fn -v; fn -v; printf '\n'

和运行这与不同(local-支持)shells:

for sh in bash dash posh zsh; do echo SH=$sh; $sh ./getopts; done

我得到的结果是:

SH=bash
'1' '' '' 
SH=dash
'1' '1' '1' 
SH=posh
'1' '' '1' 
SH=zsh
'1' '1' '1' 

造成这些差异的原因是什么? bashposh 或我的脚本有问题吗?

您需要在 getopts 循环之前将 OPTIND 设置回 1,因此它将从第一个参数开始。

bash中,OPTIND只在脚本启动时自动初始化,在zshdash中,在进入函数时初始化,并恢复到原来的状态从函数返回时的值。我不确定 posh 是做什么的。

根据 zsh 文档,您可以通过设置 POSIX_BUILTINS 选项使其行为类似于 bash。从名称来看,我假设 bash 行为符合 POSIX 要求,而 zshdash 是冲突的。