我正在为我的主题制作一个工具脚本,具有两个功能:检查更新、重新安装主题
这是选择菜单的代码:
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