6

我正在编写一个简单的 bash 脚本,它采用一个可选参数 (-t ),后跟一些附加参数。

我在想 getopts 将是实现这一目标的合理方法,但我很难获得所需的行为。我所拥有的是以下内容:

foo() {
    baz=10
    while getopts ":t:" option; do
        case "$option" in
        t) baz=$OPTARG ;;
        esac
    done
    shift $((OPTIND - 1))
    bar -t $baz $1 $2 $3
}

问题是它$OPTIND似乎并没有根据参数是否存在而有所不同,所以我没有得到预期的正确行为与可选参数(即,无论论点是否存在)。

我希望以下两项都能正确执行:

foo a b c
foo -t 5 a b c

实现这一目标的最简单方法是什么?我更喜欢不是 hack 的解决方案,因为我可能想使用其他可选参数。

4

2 回答 2

6

问题是您从不重置$OPTIND,因此每次调用foo它时,都会从最后处理的选项索引之后开始检查其参数。例如:

# $OPTIND is now 1
foo -t opt arg1 arg2 arg3
# the above recognizes -t opt as an option, and sets $OPTIND to 3

# $OPTIND is now 3
foo arg4 arg5 arg6
# the above recognizes that arg6 is not an option, so it leaves $OPTIND at 3

$OPTIND解决方案是在内进行本地化foo,将其显式设置为1

foo() {
    baz=10
    local OPTIND=1
    while getopts ":t:" option; do
        case "$option" in
        t) baz=$OPTARG ;;
        esac
    done
    shift $((OPTIND - 1))
    bar -t $baz $1 $2 $3
}

(您可能也想本地化$baz,而您正在这样做。)

于 2013-02-01T23:00:30.640 回答
4

看来您正在尝试编写 bash 函数,而不是 bash 脚本。OPTIND 在调用 shell/脚本时设置为 1,但在调用函数时不设置,因此具有不同参数的后续函数调用将在同一点继续解析​​。

如果你想保留它作为一个函数,你可以手动重置它:

foo() {
    OPTIND=1
    baz=10
    while getopts ":t:" option; do
        case "$option" in
        t) baz=$OPTARG ;;
        esac
    done
    echo $OPTIND
    shift $((OPTIND - 1))
    echo bar -t $baz $1 $2 $3
}
于 2013-02-01T22:59:27.697 回答