不同 shell 的 getopts 结果大不相同
Very different getopts results with different shells
我在 shell 脚本中做了一些选项解析,本应在 dash
和 bash
中进行内源处理,但我在 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'
造成这些差异的原因是什么? bash
和 posh
或我的脚本有问题吗?
您需要在 getopts
循环之前将 OPTIND
设置回 1
,因此它将从第一个参数开始。
在bash
中,OPTIND
只在脚本启动时自动初始化,在zsh
和dash
中,在进入函数时初始化,并恢复到原来的状态从函数返回时的值。我不确定 posh
是做什么的。
根据 zsh
文档,您可以通过设置 POSIX_BUILTINS
选项使其行为类似于 bash
。从名称来看,我假设 bash
行为符合 POSIX 要求,而 zsh
和 dash
是冲突的。
我在 shell 脚本中做了一些选项解析,本应在 dash
和 bash
中进行内源处理,但我在 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'
造成这些差异的原因是什么? bash
和 posh
或我的脚本有问题吗?
您需要在 getopts
循环之前将 OPTIND
设置回 1
,因此它将从第一个参数开始。
在bash
中,OPTIND
只在脚本启动时自动初始化,在zsh
和dash
中,在进入函数时初始化,并恢复到原来的状态从函数返回时的值。我不确定 posh
是做什么的。
根据 zsh
文档,您可以通过设置 POSIX_BUILTINS
选项使其行为类似于 bash
。从名称来看,我假设 bash
行为符合 POSIX 要求,而 zsh
和 dash
是冲突的。