首页 > 解决方案 > 重复选择菜单提示的最佳方式

问题描述

这个问答和另一个关于如何从数组中删除空白的有用答案中,我整理了一个简单的菜单对话框,允许用户在数组中“添加”和“删除”选项。然后可以将此“选定选项”数组作为输入传递给脚本/函数以执行操作。

问题:有没有比重复select循环更好的方法来重复提示?进入一个循环只是为了打破它以重复循环菜单似乎有点奇怪?

有人建议我使用select循环进行菜单选择。但我想知道是否有其他东西更适合多选菜单,因为它是动态更新的,所以应该重复提示?

我在想只是用case和使用echoprintf重复菜单对话框交换条件语句会简化脚本。但好奇是否有人知道更好的方法。

#!/bin/bash
emailAliasMenu() {
# About: Interactive two-tier menu to select Email Aliases from user input
# Usage: Pass arrays of menu items into function as argumments 1 (parent array) and 2 (child array).
# Example: startMenuTier parentMenuItems childMenuItems
    declare -n outputArray="${1}"
    initMenus() {
        parentOptMenu=("default" "add" "remove" "exit") # Parent navigation menu
        optMenu=("info" "scheduling" "hr" "contact" "feedback") # Child navigation menu
        optUnselected=("${optMenu[@]}") # Declare array for unselected options
        optSelected=() # Declare array for selected aliases
        optSelectedDef=("${optUnselected[0]}" "${optUnselected[1]}")
        PS3="$parentOptPrompt"
        dynaVars=( parentOptMenu optMenu optUnselected optSelected optSelectedDef )
        parentOptPrompt="Enter number for desired action: "
        optExitNotif="Moving up a menu..."
        errorNotif="Invalid choice. Be sure to enter a number. Try again."
    }
    removeArrayBlanks() {
        # Usage: Provide array as input. Function removes empty items and rebuilds array. 
        # Example 1: removeArrayBlanks myArray
        # Example 2: readarray -t newArray < <(removeArrayBlanks "hate" "" "empty" "array" "items")
        if [[ $# -eq 1 ]]; then # Input is an array variable.
            declare -n localArray="${1}" # Declare variable 'linked' to input (i.e. same namespace)
        elif [[ $# -gt 1 ]]; then # Input is a free array.
            declare localArray=( "${@}" ) # Put input array arguments into new array
        else echo "Usage: Provide array variable or array as an argument." && exit 1
        fi
        for i in "${!localArray[@]}"; do
            [[ -n "${localArray[${i}]}" ]] && finalArray+=( "${localArray[$i]}" ) # Add non-empty strings
        done && printf '%s\n' "${finalArray[@]}"
        localArray=( "${finalArray[@]}" ) && unset finalArray && unset -n localArray # Store new array in namespace variable and clean up
    }
    endOptMenu() {
        removeArrayBlanks optSelected
        removeArrayBlanks optUnselected
        optSummary="Selected options are: ${optSelected[*]}."
        printf '\n%s\n' "$optSummary"
    }
    unsetVars() {
        for i in "${!dynaVars[@]}"; do
            unset "${dynaVars[${i}]}"
        done
        unset -n "outputArray"
    }
    initMenus
    while true ; do # Display menu continuously until exit
        PS3="$parentOptPrompt"
        select opt in "${parentOptMenu[@]}" ; do # Parent menu for top level actions
            optPrompt="Enter number to '$opt' email alias or 'exit': " # Define prompt for child menus
            [[ $opt == "default" ]] && optSelected=("${optSelectedDef[@]}") && for i in "${optSelectedDef[@]}"
                # Uses default aliases and exits menu.
                do 
                    optUnselected=("${optUnselected[@]/$i/}")
                done && echo "$optExitNotif" && endOptMenu && break
            [[ $opt == "add" ]] && PS3="$optPrompt" && while true ; do
                select subOpt in "${optUnselected[@]}" "exit" ; do
                # Lists unselected options. Upon entry, remove and add to selected options.
                    if [[ "$subOpt" == "exit" ]]; then
                        echo "$optExitNotif" && break 3
                    elif [[ "$subOpt" ]]; then
                        optSelected+=("$subOpt") && optUnselected=("${optUnselected[@]/$subOpt/}") && endOptMenu && break 1                        
                    else
                        echo "$errorNotif" && break 1
                    fi
                done
            done
            [[ $opt == "remove" ]] && PS3="$optPrompt" && while true ; do 
                select subOpt in "${optSelected[@]}" "exit" ; do
                # Lists selected options. Upon entry, remove and add to unselected options.
                    if [[ "$subOpt" == "exit" ]]; then
                        echo "$optExitNotif" && break 3
                    elif [[ "$subOpt" ]]; then
                        optUnselected+=("$subOpt") && optSelected=("${optSelected[@]/$subOpt/}") && endOptMenu && break 1
                    else 
                        echo "$errorNotif" && break 1
                    fi
                done
            done
            [[ $opt == "exit" ]] && break 2
            [[ ! $opt ]] && echo "$errorNotif" && break 1
        done
    done
    outputArray=( "${optSelected[@]}" ) && printf '%s\n' "Final selection: ${outputArray[*]}" "Sent to array '${1}'" && unsetVars
}

标签: arraysbashloopssh

解决方案


推荐阅读