bash 使用 getopts 读取一个可选参数并移动正确数量的参数

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/14656181/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-18 04:25:36  来源:igfitidea点击:

Using getopts to read one optional parameter and shift the right number of arguments

bash

提问by jonderry

I'm writing a simple bash script that takes one optional parameter (-t ) followed by some number of additional arguments.

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

I was thinking getopts would be a reasonable way to achieve this, but I'm having difficulty getting the desired behavior. What I have is the following:

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

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

The problem is that $OPTINDdoes not seem to vary depending on whether the argument is present, so I don't get the correct behavior as expected with an optional parameter (i.e., I can't get shift to shift the right number of arguments regardless of whether the argument is there).

问题是这$OPTIND似乎并不取决于参数是否存在而变化,所以我没有通过可选参数获得预期的正确行为(即,我无法转移以转移正确数量的参数,无论论据是否存在)。

I want both of the following to execute correctly:

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

foo a b c
foo -t 5 a b c

What's the easiest way to achieve this? I'd prefer a solution that isn't a hack since I may want to use additional optional parameters.

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

采纳答案by ruakh

The problem is that you're never resetting $OPTIND, so each time you call fooit examines its arguments starting after the last processed option-index. For example:

问题是您永远不会重置$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

The solution is to localize $OPTINDwithin foo, explicitly setting it to 1:

解决方案是在$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   
}

(You probably want to localize $bazas well, while you're at it.)

(您可能还想进行本地化$baz,同时进行本地化。)

回答by that other guy

It appears that you're trying to write a bash function, not a bash script. OPTIND is set to 1 when the shell/script is invoked, but not when a function is invoked, so subsequent function calls with different arguments would continue parsing at the same point.

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

If you want to keep it as a function, you can reset it manually:

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

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   
}