在bash中创建选择菜单

时间:2017-11-08 18:11:13

标签: bash select

所以我试图为我的服务器制作一个小的自定义管理脚本,但是我遇到了一个问题,即创建具有正确结果的菜单脚本。

我有以下脚本

function config
{

list=''

declare -a programs=("docker" "IdontExist" "pushover" "IdontexistEither")

for program in "${programs[@]}"
do
    #Check if command exists on the server
    if hash $program 2>/dev/null; then
        list="${list} \"${program}\""
    fi
done



title="Config manager"
prompt="Pick an option:"
options=(${list})

echo "$title"
PS3="$prompt "

select opt in "${options[@]}" "Quit"; do
    case "$REPLY" in

    #Dont know how to create this section in a script
    1 ) echo "Update Docker"; break;;
    3 ) echo "Update IdontExist"; break;;
    2 ) echo "Update mytest"; break;;
    4 ) echo "Update IdontExistEither"; break;;

    $(( ${#options[@]}+1 )) ) echo "Goodbye!"; break;;
    *) echo "Invalid option. Try another one.";continue;;
    esac
done

}

我的列表变量如下所示

list: "docker" "pushover"

所以我在上面脚本中的选项将无法正常工作。如何创建选项,具体取决于列表变量?

我还想根据所选的选项调用某些函数,例如,如果有人选择“docker”我想调用一个名为:_docker_config的函数,当它的“pushover”我将调用一个名为_pushover_config的函数时我也在剧本中实现了这一点?

1 个答案:

答案 0 :(得分:2)

问题在于您正在测试$REPLY而不是$opt

select opt in "${options[@]}" "Quit"
do

    if [[ -z $opt ]]; then
        echo "Didn't understand \"$REPLY\" "
        REPLY=
    else
        case "$opt" in

        docker)
            echo "Update Docker"
            break;;
        IdontExist)
            echo "Update IdontExist"
            break;;
        pushover)
            echo "Update mytest"
            break;;
        IdontexistEither)
            echo "Update IdontExistEither"
            break;;
        Quit)
            echo "Goodbye!"
            break;;
        *)
           echo "Invalid option <$opt>. Try another one."
           ;;
        esac
    fi
done

如果您使用$opt,那么您不需要将菜单编号(在您的情况下是可变的)与实际条目(程序名称)匹配 - select为您执行此操作。您需要$REPLY的唯一时间是它无效(将REPLY设置为空字符串会在下一次迭代时重新显示菜单)。

并非case语句中的所有选项都适用于每次运行,但这没关系,因为$opt只会被有效的填充,而其他选项将不可见用户。

你不需要continue,它通过循环为你做到了。

编辑:

这是使用关联数组而不是case语句的替代方法。它使菜单和测试成为动态。在显示的情况下,只有两个选项具有功能,但不一定是这种情况,它可以是任何数字(有原因)。

_docker_config()
{   
    echo "Welcome to docker"
}

_pushover_config()
{   
    echo "Welcome to pushover"
}

# This declares and associative array with the keys being the menu items
# and the values being the functions to be executed.  
# This will have to include all possible programs
declare -A functab=(["Docker"]=_docker_config 
                    ["Pushover"]=_pushover_config)

title="Config manager"
prompt="Pick an option:"

# The options are hard-coded here, of course you will dynamically generate it
# I omitted that for testing purposes
declare -a options=("Docker" "IdontExist" "Pushover" "IdontexistEither")

echo "$title"
PS3="$prompt "

select opt in "${options[@]}" "Quit"
do

    if [[ $opt == "Quit" ]]; then
        echo "Goodbye!"
        break
    fi

    if [[ -z $opt ]]; then
        echo "Didn't understand \"$REPLY\" " >&2
        REPLY=
    else
        # Here we check that the option is in the associative array
        if [[ -z "${functab[$opt]}" ]]
        then
            echo "Invalid option. Try another one." >&2
        else
            # Here we execute the function
            eval ${functab[$opt]}   # See note below
        fi
    fi
done

eval 会谨慎使用。通常这是一个要避免的命令,因为它可能是一个安全问题,但是我们正在检查有效的条目,因此在这种情况下它是合理的。只是不要过度使用它。