如何在 bash 中获得 $1 后的选择

问题描述

我想以 ./script speed -a some_value -b some_value./script accuracy -a some_value -b some_value 的身份运行脚本

我尝试的是

while [ -n "$1" ]; do 

    case "$1" in

    speed)  

        for i in "${@:2}"
        do while getopts "a:b:" opt; do
            case "${opt}" in 
                a) list=$OPTARG
                    echo $list
                    ;;
                b) list2=$OPTARG
                    echo $list2
                    ;;
            esac
           done     
        done
        echo "speed option passed" 
        break ;;

    accuracy) echo "similar to above function"
              break ;;


    *) echo "Option $1 not recognized" ;; # In case you typed a different option other than a,b,c

    esac

    shift

done

获得运行./script speed -a some_value时的输出

this is something
speed option passed

我不知道这是否可行,或者有没有办法做这样的事情?

解决方法

我认为您不需要外循环 (while [ -n "$1" ]; do),除非您希望能够在一次运行中处理多个子命令。也就是说,你想要这个:

./script speed -a some_value -b some_value accuracy -a some_value -b some_value

大致相当于:

./script speed -a some_value -b some_value
./script accuracy -a some_value -b some_value

如果不是,请删除该循环,因为每次运行您将只处理一个子命令。如果您确实希望每次运行处理多个子命令,那么在运行下一个子命令之前,您需要采取一些额外的步骤来删除或跳过与一个子命令相关的参数。

确实想要删除 for i in "${@:2}" 循环——这与 getopts 的工作方式不符。您需要做的是在处理选项之前跳过子命令名称。您可以使用 shift 删除子命令名称,如下所示:

case "$1" in
    speed)
        shift    # Remove the first argument ("speed")
        while getopts "a:b:" opt; do
            ...

如果您要允许多个子命令,请在 shift $((OPTIND-1)) 循环后添加 getopts,以便为下一个子命令做好准备。

或者您可以修改 OPTIND 以告诉 getopts 它已经处理了第一个参数并且可以继续处理第二个参数:

case "$1" in
    speed)
        OPTIND=2    # Tell getopts to start processing at arg #2
        while getopts "a:b:" opt; do
            ...

如果你打算用这种方法处理多个子命令......好吧,它有点复杂,我想我会回避这个问题。

另一种选择是将每个子命令的代码放在一个函数中,并使用除第一个参数之外的所有参数调用它:

speed_subcommand() {
    local OPTIND
    while getopts "a:b:" opt; do
        ...
}

case "$1" in
    speed)
        speed_subcommand "${@:2}" ;;
    accuracy)
        accuracy_subcommand "${@:2}" ;;
    ...

这种方法并没有真正与每次运行处理多个子命令混合在一起。