我正在创建一个简单的bash脚本,并且想要在其中创建一个选择菜单,如下所示:
$./script
echo "Choose your option:"
1) Option 1
2) Option 2
3) Option 3
4) Quit
根据用户的选择,我希望执行不同的操作。我是一个bash shell脚本编写新手,我在网上搜索了一些答案,但并没有真正具体的内容。
我正在创建一个简单的bash脚本,并且想要在其中创建一个选择菜单,如下所示:
$./script
echo "Choose your option:"
1) Option 1
2) Option 2
3) Option 3
4) Quit
根据用户的选择,我希望执行不同的操作。我是一个bash shell脚本编写新手,我在网上搜索了一些答案,但并没有真正具体的内容。
Answers:
#!/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
未执行a,则该select
语句循环并重新显示菜单。
在第三个选项中,我包含了由select
语句设置的变量,以证明您可以访问这些值。如果选择它,它将输出:
you chose choice 3 which is Option 3
您可以看到其中$REPLY
包含您在提示符下输入的字符串。它用作数组的索引,${options[@]}
就好像该数组基于1。该变量$opt
包含来自数组中该索引的字符串。
请注意,选择可能是直接在select
语句中的简单列表,如下所示:
select opt in foo bar baz 'multi word choice'
但是您不能将这样的列表放入标量变量中,因为其中一个选项存在空格。
如果要在文件中进行选择,还可以使用文件遍历:
select file in *.tar.gz
./test.sh: line 9: syntax error near unexpected token
“ Option 1”'./test.sh:第9行:`“ Option 1”)'`
$options
中case
陈述,而不是值)。我认为使用这些值可以更好地说明该case
语句各节的功能。
本身并不是一个新的答案,但是由于尚无公认的答案,因此这里有一些针对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
(也可以进一步减少禅宗方法)
两者case
都是基于索引的,而不是基于价值的。我认为这更容易编码和维护
数组也用于zenity
方法。
“退出”选项不在初始的原始选项中。需要时将其“添加”,以使您的阵列保持干净。毕竟,“ zenit”并不需要“退出”,用户只需单击“取消”(或关闭窗口)即可退出。注意两者如何使用相同的未更改的选项数组。
PS3
并且REPLY
vars 无法重命名。select
被硬编码为使用它们。脚本中的所有其他变量(选项,选项,提示,标题)可以具有您想要的任何名称,只要您进行调整
case
结构,为select
您使用的版本zenity
版本:case "$opt" in . . . "${options[0]}" ) . . .
(而不是$REPLY
和索引1
,2
和3
)。
$REPLY
,索引和值之间的关系。
使用dialog
,命令如下所示:
对话框--clear --backtitle“此处的标题” --title“此处的标题” --menu“选择以下选项之一:” 15 40 4 \ 1“选项1” 2“选项2” 3“选项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
以避免在脚本在其他终端上下文中运行时发生重定向问题。
--backtitle
参数呢?
由于这是针对Ubuntu的,因此您应该使用配置为使用的任何后端debconf。您可以通过以下方式找到debconf后端:
sudo -s "echo get debconf/frontend | debconf-communicate"
如果显示“对话”,则可能使用whiptail
或dialog
。在Lucid上是whiptail
。
如果失败,请按照Dennis Williamson的说明使用bash“选择”。
#!/ bin / sh show_menu(){ normal =`echo“ \ 033 [m”` menu =`echo“ \ 033 [36m”`#蓝色 number =`echo“ \ 033 [33m”`#yellow bgred =`echo“ \ 033 [41m”`“ fgred ='echo“ \ 033 [31m”` printf“ \ n $ {menu} ********************************************** *** $ {普通} \ n“ printf“ $ {menu} ** $ {number} 1)$ {menu}挂载保管箱$ {normal} \ n” printf“ $ {menu} ** $ {number} 2)$ {menu}安装USB 500 Gig驱动器$ {normal} \ n” printf“ $ {menu} ** $ {number} 3)$ {menu}重新启动Apache $ {normal} \ n” printf“ $ {menu} ** $ {number} 4)$ {menu} ssh Frost TomCat服务器$ {normal} \ n” printf“ $ {menu} ** $ {number} 5)$ {menu}其他一些命令$ {normal} \ n” printf“ $ {menu} ************************************************ * $ {normal} \ n“ “ printf”请输入菜单选项,然后输入或$ {fgred} x退出。$ {normal}“ 阅读选项 } option_picked(){ msgcolor =`echo“ \ 033 [01; 31m”`#粗体红色 normal =`echo“ \ 033 [00; 00m”`#正常白色 message = $ {@:-“ $ {normal}错误:未传递任何消息”} printf“ $ {msgcolor} $ {message} $ {normal} \ n” } 明确 show_menu 而[$ opt!=''] 做 如果[$ opt ='']; 然后 出口; 其他 案例$ opt in 1)清除; option_picked“选择了选项1”; printf“ sudo mount / dev / sdh1 / mnt / DropBox /;#3 TB” show_menu; ;; 2)清除; option_picked“选择了选项2”; printf“ sudo mount / dev / sdi1 / mnt / usbDrive;#500 gig驱动器”; show_menu; ;; 3)清除; option_picked“选择了选项3”; printf“ sudo服务apache2重新启动”; show_menu; ;; 4)清除; option_picked“选择了选项4”; printf“ ssh lmesser @ -p 2010”; show_menu; ;; x)退出; ;; \ n)退出; ;; *)明确; option_picked“从菜单中选择一个选项”; show_menu; ;; 埃萨克 科幻 做完了
$
的$opt
变量缺少while
。该if
语句是多余的。缩进不一致。menu
在某些应该使用show_menu .
show_menu`的地方使用,可以放在循环的顶部,而不必在每个循环中重复case
。缩进不一致。单方括号和双方括号混合使用。使用硬编码的ANSI序列代替tput
。不建议使用全大写var名称。FGRED
应该叫bgred
。使用反引号代替$()
。函数定义应该一致并且不要使用...
\n
将永远不会执行。也许更多。
我使用过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
重击花式菜单
首先尝试一下,然后访问我的页面以获取详细描述...不需要外部库或对话框或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[${1};${2}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
已经在serverfault中回答了相同的问题。那里的解决方案是使用whiptail。
假设要使用普通的脚本脚本菜单(没有精美的UI),请从http://www.tldp.org/LDP/abs/html/testbranch.html查看菜单示例。
seq 10 | fzf
。缺点是默认情况下未安装fzf。您可以在这里找到fzf:github.com/junegunn/fzf