缺少选项参数时,Getopts 的行为不符合预期

Getopts behaves not as expected when option parameter is missing

我有一个带有五个位置参数的小脚本,其中前两个是可选的(-v-p),后三个是必需的(onetwo, three).第二个可选参数接受一个参数。到目前为止我有这个:

#!/bin/bash

verbose=
altpath=
while getopts ":vp:" opt; do
    case $opt in
        v)  echo "-v triggered"
            verbose=true
            ;;
        p)  echo "-p triggered, param: $OPTARG" 
            altpath=$OPTARG
            ;;
        \?) echo "invalid option: -$OPTARG."
            exit 1
            ;;
        :)  echo "option -$OPTARG requires an argument."
            exit 1
            ;;    
    esac
done

shift "$((OPTIND-1))" 

现在,如果我 运行 脚本应该是 运行,它会按预期运行:

$ myscript -v -p argname one two three

但是,如果我忘记 argname 参数

$ myscript -v -p one two three

它没有说'option -p requires an argument',而是将one作为-p的参数。显然不是我想要的。

我明白为什么会这样,但我不知道如何解决。

我建议在 getopts 完成其工作后测试是否还有三个未处理的参数。如果不是这种情况,则中止并打印一条错误消息。

例如,在脚本末尾添加:

shift "$((OPTIND-1))" 
if [ ! $# -eq 3 ] ; then
    echo "Expected three mandatory arguments"
    exit 1
fi

不直接支持如果 -p 的参数被省略则强制出错。作为一种变通方法,您可以测试下一个参数是缺失还是以破折号开头。例如:

    p)  if [ -z "$OPTARG" -o "${OPTARG:0:1}" = "-" ] ; then
            echo "Error: -p requires an argument"
            exit 1
        fi
        echo "-p triggered, param: $OPTARG" 
        altpath=$OPTARG
        ;;

这是完整的脚本:

#!/bin/bash

verbose=
altpath=
while getopts ":vp:" opt; do
    case $opt in
        v)  echo "-v triggered"
            verbose=true
            ;;
        p)  if [ -z "$OPTARG" -o "${OPTARG:0:1}" = "-" ] ; then
                echo "Error: -p requires an argument"
                exit 1
            fi
            echo "-p triggered, param: $OPTARG" 
            altpath=$OPTARG
            ;;
        \?) echo "invalid option: -$OPTARG."
            exit 1
            ;;
        :)  echo "option -$OPTARG requires an argument."
            exit 1
            ;;    
    esac
done

shift "$((OPTIND-1))" 
if [ ! $# -eq 3 ] ; then
    echo "Expected three mandatory arguments"
    exit 1
fi