如何使 bash getopts 无法将选项识别为选项参数

How make bash getopts not recognize option as a option argument

在我的 bash 脚本中,我想使用 getopts 来解析命令行选项。

我第一次尝试学习如何使用它,如下所示:

#!/bin/bash

v_option_arg=""
r_option_arg=""
h_option_arg=""

function get_opt_args() {
    while getopts ":v:r:h:" opt
    do
        case $opt in
        "v")
            v_option_arg="$OPTARG"
             ;;
        "h")
            h_option_arg="$OPTARG"
            ;;
        "r")
            r_option_arg="$OPTARG"
            ;;
        "?")
            echo "Unknown option -$OPTARG"
            exit 1
            ;;
        ":")
            echo "No argument value for option -$OPTARG"
            ;;
        *)
            # Should not occur
            echo "Unknown error while processing options"
            ;;
        esac
    done
    shift $((OPTIND-1))
}

get_opt_args $@
if [ ! -z "$v_option_arg" ]; then
    echo "Argnument value for option -v: $v_option_arg"
fi
if [ ! -z "$r_option_arg" ]; then
    echo "Argnument value for option -r: $r_option_arg"
fi
if [ ! -z "$h_option_arg" ]; then
    echo "Argnument value for option -h: $h_option_arg"
fi
$ bash testopts.sh -v 1
Argnument value for option -v: 1
$ bash testopts.sh -r 2
Argnument value for option -r: 2
$ bash testopts.sh -h 3
Argnument value for option -h: 3
$ bash testopts.sh -v 1 -r 2 -h 3
Argnument value for option -v: 1
Argnument value for option -r: 2
Argnument value for option -h: 3
$ bash testopts.sh -v
No argument value for option -v
$ bash testopts.sh -a
Unknown option -a

这似乎成功了。

接下来,我通过省略一个参数来测试我的脚本的健壮性:

$ bash testopts.sh -v -r 2
Argnument value for option -v: -r

这不是我所期待的。如何让它区分一个选项和一个选项参数的区别?

我想让我的脚本更健壮,这样如果给出一个没有参数的选项,我可以发出合适的错误消息。

注意:每个选项都必须有一个选项参数。

我可以只使用 getopts 吗?

来自 man bash,SHELL 内置命令,getopts:

optstring contains the option characters to be recognized; if a character is followed by a colon, the option is expected to have an argument, which should be separated from it by white space.

来自您的脚本:

while getopts ":v:r:h:" opt

您明确告诉 bash -v 需要一个参数。在 -v -r 2 的情况下,-r-v 的参数,2 保留为脚本的非选项参数。

按设计工作,这是 getopts 能力的极限。

可以 做的是检查 -v 的参数是否是数字(因为这似乎是你的脚本所期望的),并在给定的情况下通知-v 确实的用户需要一个数字,而-r不是。但这是您的脚本在 "v") 情况下需要做的事情,而不是 getopts 可以处理的事情。

    case $opt in
    "v")
        v_option_arg="$OPTARG"
        if [[ ! "${v_option_arg}" =~ ^[0-9]*$ ]]
        then
            echo "Error: Option '-v' expects numeric argument, you gave: ${v_option_arg}"
            exit 1
        fi
         ;;