$./script
echo "Choose your option:"
1) Option 1
2) Option 2
3) Option 3
4) Quit
并且根据用户的选择,我希望执行不同的操作。我是一个bash shell脚本编写专家,我在网上搜索了一些答案,但并没有什么具体的答案。
#1 楼
#!/bin/bash
# Bash Menu Script Example
PS3='Please enter your choice: '
options=("Option 1" "Option 2" "Option 3" "Quit")
select opt in "${options[@]}"
do
case $opt in
"Option 1")
echo "you chose choice 1"
;;
"Option 2")
echo "you chose choice 2"
;;
"Option 3")
echo "you chose choice $REPLY which is $opt"
;;
"Quit")
break
;;
*) echo "invalid option $REPLY";;
esac
done
在需要
break
循环退出的任何地方添加select
语句。如果未执行break
,则select
语句循环并重新显示菜单。在第三个选项中,我包括了
select
语句设置的变量,以证明您可以访问这些变量。价值观。如果选择它,它将输出:you chose choice 3 which is Option 3
您可以看到
$REPLY
包含您在提示符下输入的字符串。它用作数组${options[@]}
的索引,就好像该数组基于1。变量$opt
包含数组中该索引的字符串。请注意,选择可能是直接在
select
语句中的简单列表,如下所示:select opt in foo bar baz 'multi word choice'
,但是由于其中一个选项的空格,您不能将这样的列表放在标量变量中。 br />
select file in *.tar.gz
评论
@Abdull:这是预期的行为。 “ Quit”选项执行一个中断,该中断脱离选择循环。您可以在任何需要的地方添加中断。 Bash手册指出:“每次选择后都会执行命令,直到执行break命令为止,此时select命令完成。”
–丹尼斯·威廉姆森
2015年12月7日在17:31
FWIW,使用GNU bash 4.3.11在14.04上运行此代码,会在第9行产生错误:./test.sh:第9行:意外标记“ Option 1”附近的语法错误。./test.sh:第9行:““ Option 1 “)'`
–布莱恩·布朗顿(Brian Brownton)
16 Dec 8'在14:59
该PS3变量是什么?为什么在分配后根本不引用它?
– dtmland
17年11月30日在17:59
@dtmland:PS3是select命令的提示符。它是自动使用的,不需要显式引用。 PS3和选择文档。
–丹尼斯·威廉姆森
17年11月30日在20:55
@Christian:不,不应该(但是如果我在case语句中使用$ options的索引而不是值,可以这样做)。我认为使用这些值可以更好地记录case语句各节的功能。
–丹尼斯·威廉姆森
19年7月11日在12:33
#2 楼
使用dialog
,命令将如下所示:dialog --clear --backtitle "Backtitle here" --title "Title here" --menu "Choose one of the following options:" 15 40 4 \ 1 "Option 1" \ 2 "Option 2" \ 3 "Option 3"
将其放入脚本中:
#!/bin/bash
HEIGHT=15
WIDTH=40
CHOICE_HEIGHT=4
BACKTITLE="Backtitle here"
TITLE="Title here"
MENU="Choose one of the following options:"
OPTIONS=(1 "Option 1"
2 "Option 2"
3 "Option 3")
CHOICE=$(dialog --clear \
--backtitle "$BACKTITLE" \
--title "$TITLE" \
--menu "$MENU" \
$HEIGHT $WIDTH $CHOICE_HEIGHT \
"${OPTIONS[@]}" \
2>&1 >/dev/tty)
clear
case $CHOICE in
1)
echo "You chose Option 1"
;;
2)
echo "You chose Option 2"
;;
3)
echo "You chose Option 3"
;;
esac
评论
我想指出,我在脚本顶部放置了TERMINAL = $(tty)行,然后在CHOICE变量定义中将2>&1> / dev / tty更改为2>&1> $ TERMINAL,以避免重定向如果脚本在其他终端上下文中运行,则会出现问题。
–Shrout1
18年6月12日在14:37
--backtitle参数有什么作用?
– TRiG
18年8月31日在23:22
它是背景中蓝屏的标题。您可以在屏幕截图的左上角看到它,上面写着“ Backtitle here”。
– Alaa Ali
18年8月31日在23:25
#3 楼
本身不是一个新的答案,但是由于尚无公认的答案,因此这里有一些针对select和zenity的编码技巧和窍门: title="Select example"
prompt="Pick an option:"
options=("A" "B" "C")
echo "$title"
PS3="$prompt "
select opt in "${options[@]}" "Quit"; do
case "$REPLY" in
1 ) echo "You picked $opt which is option $REPLY";;
2 ) echo "You picked $opt which is option $REPLY";;
3 ) echo "You picked $opt which is option $REPLY";;
$(( ${#options[@]}+1 )) ) echo "Goodbye!"; break;;
*) echo "Invalid option. Try another one.";continue;;
esac
done
while opt=$(zenity --title="$title" --text="$prompt" --list \
--column="Options" "${options[@]}"); do
case "$opt" in
"${options[0]}" ) zenity --info --text="You picked $opt, option 1";;
"${options[1]}" ) zenity --info --text="You picked $opt, option 2";;
"${options[2]}" ) zenity --info --text="You picked $opt, option 3";;
*) zenity --error --text="Invalid option. Try another one.";;
esac
done
值得一提:
两者都会循环播放,直到用户明确选择“退出”(或取消“取消”)。这是用于交互式脚本菜单的好方法:选择一个选项并执行操作后,将再次显示菜单以供另一个选择使用。如果选择仅是一次性的,则只需在
break
之后使用esac
(也可以进一步减少zenity方法)。case
均基于索引,而不是基于值。我认为这易于编码和维护。数组也用于
zenity
方法。“退出”选项不在初始的原始选项中。需要时将其“添加”,以使您的阵列保持干净。毕竟,“ zenit”并不需要“退出”,用户只需单击“取消”(或关闭窗口)即可退出。请注意,它们如何使用相同的未更改的选项数组。
PS3
和REPLY
变量不能重命名。 select
被硬编码为使用它们。脚本中的所有其他变量(选项,选项,提示,标题)可以具有您想要的任何名称,只要您进行调整评论
很棒的解释。谢谢。这个问题在Google上仍然排名很高,所以很遗憾它已经关闭。
–MountainX
13年6月30日在8:44
您可以为zenity版本使用相同的大小写结构用于选择版本:中的case“ $ opt”。 。 。 “ $ {options [0]}”))。 。 。 (而不是$ REPLY和索引1、2和3)。
–丹尼斯·威廉姆森
18年5月29日在20:40
@DennisWilliamson,是的,我可以,在“真实”代码中,最好在两种情况下都使用相同的结构。我故意要显示$ REPLY,索引和值之间的关系。
–MestreLion
18年5月31日在20:28
#4 楼
您可以使用这个简单的脚本来创建选项#!/bin/bash echo "select the operation ************" echo " 1)operation 1" echo " 2)operation 2" echo " 3)operation 3" echo " 4)operation 4" read n case $n in 1) echo "You chose Option 1";; 2) echo "You chose Option 2";; 3) echo "You chose Option 3";; 4) echo "You chose Option 4";; *) echo "invalid option";; esac
#5 楼
我还有一个混合了这些答案的选项,但很高兴的是,您只需要按一个键,然后通过read的-n
选项就可以继续执行脚本。在此示例中,我们提示关闭,重新启动或仅使用ANS
作为我们的变量退出脚本,并且用户仅需按E,R或S。我还将默认值设置为退出,因此如果按Enter,则按脚本将退出。 read -n 1 -p "Would you like to exit, reboot, or shutdown? (E/r/s) " ans;
case $ans in
r|R)
sudo reboot;;
s|S)
sudo poweroff;;
*)
exit;;
esac
#6 楼
#!/bin/sh show_menu(){ normal=`echo "3[m"` menu=`echo "3[36m"` #Blue number=`echo "3[33m"` #yellow bgred=`echo "3[41m"` fgred=`echo "3[31m"` printf "\n${menu}*********************************************${normal}\n" printf "${menu}**${number} 1)${menu} Mount dropbox ${normal}\n" printf "${menu}**${number} 2)${menu} Mount USB 500 Gig Drive ${normal}\n" printf "${menu}**${number} 3)${menu} Restart Apache ${normal}\n" printf "${menu}**${number} 4)${menu} ssh Frost TomCat Server ${normal}\n" printf "${menu}**${number} 5)${menu} Some other commands${normal}\n" printf "${menu}*********************************************${normal}\n" printf "Please enter a menu option and enter or ${fgred}x to exit. ${normal}" read opt } option_picked(){ msgcolor=`echo "3[01;31m"` # bold red normal=`echo "3[00;00m"` # normal white message=${@:-"${normal}Error: No message passed"} printf "${msgcolor}${message}${normal}\n" } clear show_menu while [ $opt != '' ] do if [ $opt = '' ]; then exit; else case $opt in 1) clear; option_picked "Option 1 Picked"; printf "sudo mount /dev/sdh1 /mnt/DropBox/; #The 3 terabyte"; show_menu; ;; 2) clear; option_picked "Option 2 Picked"; printf "sudo mount /dev/sdi1 /mnt/usbDrive; #The 500 gig drive"; show_menu; ;; 3) clear; option_picked "Option 3 Picked"; printf "sudo service apache2 restart"; show_menu; ;; 4) clear; option_picked "Option 4 Picked"; printf "ssh lmesser@ -p 2010"; show_menu; ;; x)exit; ;; \n)exit; ;; *)clear; option_picked "Pick an option from the menu"; show_menu; ;; esac fi done
评论
我知道这很旧,但是需要第一行读取#!/ bin / bash才能进行编译。
– JClar
2014-12-7 12:15
代码审查:while语句中$ opt变量中缺少$。 if语句是多余的。缩进不一致。在某些应该使用“ show_menu”的地方使用菜单。 show_menu`可以放在循环的顶部,而不是在每种情况下都重复。缩进不一致。单方括号和双方括号混合使用。使用硬编码的ANSI序列而不是tput。不建议使用全大写var名称。 FGRED应该被称为bgred。使用反引号代替$()。函数定义应该一致,不要使用...
–丹尼斯·威廉姆森
18年5月29日在20:57
两者一起形成不需要终端分号。一些颜色等定义了两次。 \ n的情况将永远不会执行。也许更多。
–丹尼斯·威廉姆森
18年5月29日在21:01
#7 楼
由于这是针对Ubuntu的,因此您应该使用配置为使用的任何后端debconf。您可以通过以下方式找到debconf后端:sudo -s "echo get debconf/frontend | debconf-communicate"
如果显示“ dialog”,则可能使用
whiptail
或dialog
。在Lucid上为whiptail
。如果失败,请使用bash“ select”,如Dennis Williamson所述。
评论
对于这个问题,这可能是多余的,但是提及鞭尾和对话则为+1!我没有意识到那些命令...非常贴心!
–MestreLion
2011年8月5日下午5:58
#8 楼
我使用过Zenity,它在Ubuntu中似乎总是存在,工作得很好并且具有很多功能。这是一个可能的菜单的示意图:#! /bin/bash
selection=$(zenity --list "Option 1" "Option 2" "Option 3" --column="" --text="Text above column(s)" --title="My menu")
case "$selection" in
"Option 1")zenity --info --text="Do something here for No1";;
"Option 2")zenity --info --text="Do something here for No2";;
"Option 3")zenity --info --text="Do something here for No3";;
esac
评论
糟糕!抱歉,此代码段的外观是第一次发布,似乎不得不关闭HTML
– LazyEchidna
2011年5月5日,下午1:36
更好的是,在编辑中启用了“代码示例”,对此感到抱歉
– LazyEchidna
2011年5月5日,下午1:47
#9 楼
Bash精美菜单先尝试一下,然后访问我的页面以获取详细说明...
不需要外部库或对话框或Zenity之类的程序...
#/bin/bash
# by oToGamez
# www.pro-toolz.net
E='echo -e';e='echo -en';trap "R;exit" 2
ESC=$( $e "\e")
TPUT(){ $e "\e[;H";}
CLEAR(){ $e "\ec";}
CIVIS(){ $e "\e[?25l";}
DRAW(){ $e "\e%@\e(0";}
WRITE(){ $e "\e(B";}
MARK(){ $e "\e[7m";}
UNMARK(){ $e "\e[27m";}
R(){ CLEAR ;stty sane;$e "\ec\e[37;44m\e[J";};
HEAD(){ DRAW
for each in $(seq 1 13);do
$E " x x"
done
WRITE;MARK;TPUT 1 5
$E "BASH SELECTION MENU ";UNMARK;}
i=0; CLEAR; CIVIS;NULL=/dev/null
FOOT(){ MARK;TPUT 13 5
printf "ENTER - SELECT,NEXT ";UNMARK;}
ARROW(){ read -s -n3 key 2>/dev/null >&2
if [[ $key = $ESC[A ]];then echo up;fi
if [[ $key = $ESC[B ]];then echo dn;fi;}
M0(){ TPUT 4 20; $e "Login info";}
M1(){ TPUT 5 20; $e "Network";}
M2(){ TPUT 6 20; $e "Disk";}
M3(){ TPUT 7 20; $e "Routing";}
M4(){ TPUT 8 20; $e "Time";}
M5(){ TPUT 9 20; $e "ABOUT ";}
M6(){ TPUT 10 20; $e "EXIT ";}
LM=6
MENU(){ for each in $(seq 0 $LM);do M${each};done;}
POS(){ if [[ $cur == up ]];then ((i--));fi
if [[ $cur == dn ]];then ((i++));fi
if [[ $i -lt 0 ]];then i=$LM;fi
if [[ $i -gt $LM ]];then i=0;fi;}
REFRESH(){ after=$((i+1)); before=$((i-1))
if [[ $before -lt 0 ]];then before=$LM;fi
if [[ $after -gt $LM ]];then after=0;fi
if [[ $j -lt $i ]];then UNMARK;M$before;else UNMARK;M$after;fi
if [[ $after -eq 0 ]] || [ $before -eq $LM ];then
UNMARK; M$before; M$after;fi;j=$i;UNMARK;M$before;M$after;}
INIT(){ R;HEAD;FOOT;MENU;}
SC(){ REFRESH;MARK;$S;$b;cur=`ARROW`;}
ES(){ MARK;$e "ENTER = main menu ";$b;read;INIT;};INIT
while [[ "$O" != " " ]]; do case $i in
0) S=M0;SC;if [[ $cur == "" ]];then R;$e "\n$(w )\n";ES;fi;;
1) S=M1;SC;if [[ $cur == "" ]];then R;$e "\n$(ifconfig )\n";ES;fi;;
2) S=M2;SC;if [[ $cur == "" ]];then R;$e "\n$(df -h )\n";ES;fi;;
3) S=M3;SC;if [[ $cur == "" ]];then R;$e "\n$(route -n )\n";ES;fi;;
4) S=M4;SC;if [[ $cur == "" ]];then R;$e "\n$(date )\n";ES;fi;;
5) S=M5;SC;if [[ $cur == "" ]];then R;$e "\n$($e by oTo)\n";ES;fi;;
6) S=M6;SC;if [[ $cur == "" ]];then R;exit 0;fi;;
esac;POS;done
评论
这仅适用于bash,有点酷。
–雷顿·埃弗森(Layton Everson)
2015年11月17日下午0:35
真好! “然后访问我的页面以获取详细描述”是否存在链接?
–橡木
15年12月14日在13:36
pro-toolz.net/data/programming/bash/Bash_fancy_menu.html
–jobwat
16年6月7日在5:08
在此服务器上找不到请求的URL /data/programming/bash/Bash_fancy_menu.html。
–MountainX
19/12/9在1:40
#10 楼
已经在serverfault中回答了相同的问题。那里的解决方案使用鞭尾。评论
谢谢,但是由于我的脚本用于主流消费,所以我不希望它具有任何其他依赖。但我知道,我会将其标记为将来使用。
–丹尼尔·罗德里格斯(Daniel Rodrigues)
2010年8月8日在22:01
#11 楼
假设您要使用一个普通的shell脚本菜单(没有精美的UI),请从http://www.tldp.org/LDP/abs/html/testbranch.html中查看菜单示例。评论
与高级bash脚本指南中的许多其他代码段一样,这些代码段包含错误和不良做法。
– Geirha
2011年2月3日23:39
评论
这个问题是古老且受保护的,但我使用fzf。尝试seq 10 | fzf。缺点是默认情况下未安装fzf。您可以在这里找到fzf:github.com/junegunn/fzf