bash - 选择并执行选择后如何重新显示选择菜单

bash - 选择并执行选择后如何重新显示选择菜单

我正在为我的主题制作一个工具脚本,具有两个功能:检查更新、重新安装主题

这是选择菜单的代码:

PS3='Choose an option: '
options=("Check for update" "Reinstall theme")
select opt in "${options[@]}"
do
     case $opt in
             "Check for update")
                       echo "Checking update"
                               ;;
             "Reinstall theme")
                       echo "Reinstalling"
                               ;;
                               *) echo invalid option;;
     esac
done

运行的时候会出现这样的情况

1) Check for update
2) Reinstall theme
Choose an option:

我输入 1 并回车,执行更新命令检查

问题是当它完成执行脚本时,它重新显示“选择一个选项:”而不是菜单。因此,如果没有菜单,用户可能很难选择(尤其是在很长的脚本之后)

1) Check for update
2) Reinstall theme
Choose an option: 1
Checking update
Choose an option:

那么如何在执行选项后重新显示菜单

答案1

我猜你真的想要这样的东西:

check_update () {
    echo "Checking update"
}

reinstall_theme () {
    echo "Reinstalling theme"
}

while true; do
    options=("Check for update" "Reinstall theme")

    echo "Choose an option:"
    select opt in "${options[@]}"; do
        case $REPLY in
            1) check_update; break ;;
            2) reinstall_theme; break ;;
            *) echo "What's that?" >&2
        esac
    done

    echo "Doing other things..."

    echo "Are we done?"
    select opt in "Yes" "No"; do
        case $REPLY in
            1) break 2 ;;
            2) break ;;
            *) echo "Look, it's a simple question..." >&2
        esac
    done
done

我已将任务分成单独的函数,以保持第一个case语句更小。我还在语句$REPLY中使用了而不是选项字符串,case因为它更短,并且如果您决定更改它们但忘记在两个地方更新它们也不会中断。我还选择不触摸,PS3因为这可能会影响select脚本中的后续调用。如果我想要不同的提示,我会设置一次并保留它(也许PS3="Your choice: ")。这将使包含多个问题的脚本具有更统一的感觉。

我添加了一个外部循环,它会迭代所有内容,直到用户完成为止。您需要此循环来重新显示第一个语句中的问题select

我已经添加了break语句case,否则除了中断脚本之外没有办法退出。

a 的目的select是从用户那里获得一个问题的答案,而不是真正成为脚本的主要事件循环(本身)。一般来说,a select-case实际上应该只设置一个变量或调用一个函数,然后继续。

一个较短的版本,在第一个版本中包含“退出”选项select

check_update () {
    echo "Checking update"
}

reinstall_theme () {
    echo "Reinstalling theme"
}

while true; do
    options=("Check for update" "Reinstall theme" "Quit")

    echo "Choose an option: "
    select opt in "${options[@]}"; do
        case $REPLY in
            1) check_update; break ;;
            2) reinstall_theme; break ;;
            3) break 2 ;;
            *) echo "What's that?" >&2
        esac
    done
done

echo "Bye bye!"

答案2

你的 do 循环是无限的,你的 select 语句在它之外。该脚本执行一次 select 语句,然后停留在 do 循环中一遍又一遍地检查 case $opt 。我的建议是在你的案例陈述之后添加中断,如下所示:

esac
break
done

然后,如果您确实希望整个脚本一遍又一遍地重复,请创建另一个循环来包含从 select 语句到 did 语句的所有内容。

答案3

我用这个技巧:

options=("First option" "Second option" "Quit")
PS3="So what? "
select opt in "${options[@]}"
do
    case $opt in
        "First option")
            echo "First option"
            ;;
        "Second option")
            echo "Second option"    
            ;;
        "Quit")
            echo "We are done..."
            break
            ;;
        *) 
            PS3="" # this hides the prompt
            echo asdf | select foo in "${options[@]}"; do break; done # dummy select 
            PS3="So what? " # this displays the common prompt
            ;;
    esac
done

答案4

你也可以检查我的方法,我通过一个简单的循环function处理它for

for((i=0;i<${#opt[@]};i++));do echo "$((i+1))) ${opt[$i]}";done

这是我的示例代码:

msg="Choose an option:"
opt=("Check_for_update" "Reinstall_theme")

refresh_the_list(){
echo -e "\n$msg"
for((i=0;i<${#opt[@]};i++))
do
        echo "$((i+1))) ${opt[$i]}"
done
}
echo $msg
select i in ${opt[@]}
do
        case $i in
                        ${opt[0]})
                                echo "Checking update"
                                refresh_the_list;;
                        ${opt[1]})
                                echo "Reinstalling"
                                refresh_the_list;;
                        *)
                                echo "invalid option"
                                refresh_the_list;;
        esac
done

相关内容