bash getopts,仅短选项,都需要值,自己的验证

bat*_*tad 8 bash getopts

我正在尝试构建一个接受各种选项的 shell 脚本,这getopts似乎是一个很好的解决方案,因为它可以处理选项和参数的可变排序(我认为!)。

我只会使用短选项,每个短选项都需要一个相应的值,例如:./command.sh -a arga -g argg -b argb但我希望允许以非特定顺序输入选项,这是大多数人习惯使用 shell 命令的方式.

另一点是我想自己检查选项参数值,最好是在case语句中。这样做的原因是我:)case声明中的测试产生了不一致的结果(可能是由于我缺乏理解)。
例如:

#!/bin/bash
OPTIND=1 # Reset if getopts used previously
if (($# == 0)); then
        echo "Usage"
        exit 2
fi
while getopts ":h:u:p:d:" opt; do
        case "$opt" in

                h)
                        MYSQL_HOST=$OPTARG
                        ;;
                u)
                        MYSQL_USER=$OPTARG
                        ;;
                p)
                        MYSQL_PASS=$OPTARG
                        ;;
                d)
                        BACKUP_DIR=$OPTARG
                        ;;
                \?)
                        echo "Invalid option: -$OPTARG" >&2
                        exit 2;;
                :)
                       echo "Option -$OPTARG requires an argument" >&2
                       exit 2;;
        esac
done
shift $((OPTIND-1))
echo "MYSQL_HOST='$MYSQL_HOST'  MYSQL_USER='$MYSQL_USER'  MYSQL_PASS='$MYSQL_PASS'  BACKUP_DIR='$BACKUP_DIR' Additionals: $@"
Run Code Online (Sandbox Code Playgroud)

像这样的事件失败了......./command.sh -d -h
当我希望它将 -d 标记为需要参数但我得到的值-d=-h不是我需要的值时。

所以我认为在 case 语句中运行我自己的验证会更容易,以确保每个选项只设置一次。

我正在尝试执行以下操作,但未if [ ! "$MYSQL_HOST" ]; then触发我的块。

OPTIND=1 # Reset if getopts used previously

if (($# == 0)); then
        echo "Usage"
        exit 2
fi

while getopts ":h:u:p:d:" opt; do
        case "$opt" in

                h)
                        MYSQL_HOST=$OPTARG
                        if [ ! "$MYSQL_HOST" ]; then
                                echo "host not set"
                                exit 2
                        fi
                        ;;
                u)
                        MYSQL_USER=$OPTARG
                        if [ ! "$MYSQL_USER" ]; then
                                echo "username not set"
                                exit 2
                        fi
                        ;;
                p)
                        MYSQL_PASS=$OPTARG
                        if [ ! "$MYSQL_PASS" ]; then
                                echo "password not set"
                                exit 2
                        fi
                        ;;
                d)
                        BACKUP_DIR=$OPTARG
                        if [ ! "$BACKUP_DIR" ]; then
                                echo "backup dir not set"
                                exit 2
                        fi
                        ;;
                \?)
                        echo "Invalid option: -$OPTARG" >&2
                        exit 2;;
                #:)
                #       echo "Option -$opt requires an argument" >&2
                #       exit 2;;
        esac
done
shift $((OPTIND-1))

echo "MYSQL_HOST='$MYSQL_HOST'  MYSQL_USER='$MYSQL_USER'  MYSQL_PASS='$MYSQL_PASS'  BACKUP_DIR='$BACKUP_DIR' Additionals: $@"
Run Code Online (Sandbox Code Playgroud)

是否有原因我无法OPTARG从内部检查 a 是否具有零长度getopts ... while ... case

有什么更好的方式来与经营自己的参数验证getopts的情况下,我不希望被依靠:)。在while ... case ... esac?之外执行我的参数验证
然后我可以得到-detc 的参数值,而不是捕捉到丢失的选项。

Ant*_*hon 4

当您使用以下命令调用第二个脚本(我将其保存为getoptit)时:

getoptit -d -h
Run Code Online (Sandbox Code Playgroud)

这将打印:

MYSQL_HOST=''  MYSQL_USER=''  MYSQL_PASS=''  BACKUP_DIR='-h' Additionals: 
Run Code Online (Sandbox Code Playgroud)

所以 BACKUP_DIR 已设置,并且您正在测试if [ ! "$BACKUP_DIR" ]; then这样就设置了BACKUP_DIR,如果没有设置则

如果您想测试每个选项是否设置一次,则必须在根据 $OPTARG 值进行分配之前执行此操作。在分配之前,您可能还应该检查 $OPTARG 是否以 a 开头'-'(针对错误):-d -h

...
            d)
                    if [ ! -z "$BACKUP_DIR" ]; then
                            echo "backup dir already set"
                            exit 2
                    fi
                    if [ z"${OPTARG:0:1}" == "z-" ]; then
                            echo "backup dir starts with option string"
                            exit 2
                    fi
                    BACKUP_DIR=$OPTARG
                    ;;
...
Run Code Online (Sandbox Code Playgroud)