如何在shell脚本中创建选择菜单?

我正在创建一个简单的bash脚本,我想在其中创建一个选择菜单,如下所示:

$./script echo "Choose your option:" 1) Option 1 2) Option 2 3) Option 3 4) Quit 

根据用户的选择,我希望执行不同的操作。 我是一个bash shell脚本菜鸟,我在网上搜索了一些答案,但没有什么真正具体的。

 #!/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 

在需要select循环退出的地方添加break语句。 如果未执行break ,则select语句循环并重新显示菜单。

在第三个选项中,我包含了由select语句设置的变量,以certificate您可以访问这些值。 如果你选择它,它将输出:

 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 

本身并不是一个新的答案,但由于还没有接受的答案,这里有一些编码提示和技巧,对于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 

值得一提:

  • 两者都将循环,直到用户明确选择退出(或取消为zenity)。 这是交互式脚本菜单的一种很好的方法:选择一个选项并执行操作后,再次显示菜单以供另一个选择。 如果选择只是一次性的,那么只需在esac之后使用break (zenity方法也可以进一步减少)

  • 这两种case都是基于指数的,而不是基于价值的。 我认为这更容易编码和维护

  • 数组也用于zenity方法。

  • “退出”选项不属于最初的原始选项。 它在需要时“添加”,因此您的arrays保持清洁。 毕竟,无论如何,zenity都不需要“退出”,用户只需单击“取消”(或关闭窗口)即可退出。 注意两者是如何使用相同的,未触及的选项数组。

  • PS3REPLY变量无法重命名。 select被硬编码以使用它们。 脚本中的所有其他变量(opt,options,prompt,title)可以包含您想要的任何名称,前提是您进行了调整

使用dialog ,命令将如下所示:

  dialog --clear --backtitle“Backtitle here” - 标题“Title here”--menu“选择以下选项之一:”15 40 4 \
 1“选项1”
 2“选项2”
 3“选项3”

在此处输入图像描述

把它放在一个脚本中:

 #!/斌/庆典

 HEIGHT = 15
 WIDTH = 40
 CHOICE_HEIGHT = 4
 BACKTITLE =“Backtitle here”
 TITLE =“标题在这里”
 MENU =“选择以下选项之一:”

选项=(1“选项1”
          2“选项2”
          3“选项3”)

选择= $(对话 - 清晰\
                 --backtitle“$ BACKTITLE”\
                 - 标题“$ TITLE”
                 --menu“$ MENU”\
                 $ HEIGHT $ WIDTH $ CHOICE_HEIGHT \
                 “$ {OPTIONS [@]}”
                 2>&1> / dev / tty)

明确
案例$ CHOICE in
         1)
             echo“你选择了选项1”
             ;;
         2)
             echo“你选择了Option 2”
             ;;
         3)
             echo“你选择了选项3”
             ;;
 ESAC

您可以使用此简单脚本来创建选项

 #!/bin/bash echo "select the operation ************ 1)operation 1 2)operation 2 3)operation 3 4)operation 4 " read n case $n in 1) commands for opn 1;; 2) commands for opn 2;; 3) commands for opn 3;; 4) commands for opn 4;; *) invalid option;; esac 

由于这是针对Ubuntu的,因此您应该使用配置为使用的任何后端debconf。 你可以找到debconf后端:

 sudo -s "echo get debconf/frontend | debconf-communicate" 

如果它说“对话”,那么它可能使用whiptaildialog 。 在Lucid上它是whiptail

如果失败,请按照丹尼斯威廉姆森的解释使用bash“select”。

我使用过Zenity,它似乎总是存在于Ubuntu中,效果很好并且具有很多function。 这是一个可能的菜单草图:

 #! /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 
  #!/ bin / sh的
 show_menu(){
     NORMAL =`echo“\ 033 [m”`
     MENU =`echo“\ 033 [36m”`#Blue
     NUMBER =`echo“\ 033 [33m”`#yellow
     FGRED =`echo“\ 033 [41m”`
     RED_TEXT =`echo“\ 033 [31m”`
     ENTER_LINE =`echo“\ 033 [33m”`
     echo -e“$ {MENU} ****************************************** *** $ {}师范大学”
     echo -e“$ {MENU} ** $ {NUMBER} 1)$ {MENU}挂载dropbox $ {NORMAL}”
     echo -e“$ {MENU} ** $ {NUMBER} 2)$ {MENU}安装USB 500 Gig Drive $ {NORMAL}”
     echo -e“$ {MENU} ** $ {NUMBER} 3)$ {MENU}重启Apache $ {NORMAL}”
     echo -e“$ {MENU} ** $ {NUMBER} 4)$ {MENU} ssh Frost TomCat Server $ {NORMAL}”
     echo -e“$ {MENU} ** $ {NUMBER} 5)$ {MENU} $ {NORMAL}”
     echo -e“$ {MENU} ****************************************** *** $ {}师范大学”
     echo -e“$ {ENTER_LINE}请输入一个菜单选项并输入或$ {RED_TEXT}进入退出。$ {NORMAL}”
    阅读选择
 }
 function option_picked(){
     COLOR ='\ 033 [01; 31m'#粗体红
     RESET ='\ 033 [00; 00m'#正常白色
     MESSAGE = $ {@: - “$ {RESET}错误:未传递任何消息”}
     echo -e“$ {COLOR} $ {MESSAGE} $ {RESET}”
 }

明确
 show_menu
而[opt!='']
    做
     if [[$ opt =“”]]; 然后 
            出口;
    其他
         case $ opt in
         1)清楚;
         option_picked“Option 1 Picked”;
         sudo mount / dev / sdh1 / mnt / DropBox /;  #3 TB
        菜单;
         ;;

         2)清楚;
             option_picked“Option 2 Picked”;
             sudo mount / dev / sdi1 / mnt / usbDrive;  #The 500 gig drive
        菜单;
             ;;

         3)清楚;
             option_picked“Option 3 Picked”;
         sudo service apache2 restart;
             show_menu;
             ;;

         4)清楚;
             option_picked“Option 4 Picked”;
         ssh lmesser @ -p 2010;
             show_menu;
             ;;

         x)的出口;
         ;;

         \ n)的出口;
         ;;

         *)明确;
         option_picked“从菜单中选择一个选项”;
         show_menu;
         ;;
     ESAC
科幻
 DONE

Bash花式菜单

首先尝试一下,然后访问我的页面进行详细描述……不需要外部库或对话或zenity等程序……

 #/斌/庆典
 #by oToGamez
 #www.pro-toolz.net

       E ='echo -e'; e ='echo -en';陷阱“R;退出”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
            $(seq 1 13)中的每一个;做
            $ E“xx”
            DONE
            WRITE; MARK; TPUT 1 5
            $ E“BASH SELECTION MENU”; UNMARK;}
            I = 0; 明确;  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]];然后回显; fi
           如果[[$ key = $ ESC [B]];那么echo dn; fi;}
      M0(){TPUT 4 20;  $ e“登录信息”;}
      M1(){TPUT 5 20;  $ e“网络”;}
      M2(){TPUT 6 20;  $ e“磁盘”;}
      M3(){TPUT 7 20;  $ e“路由”;}
      M4(){TPUT 8 20;  $ e“时间”;}
      M5(){TPUT 9 20;  $ e“关于”;}
      M6(){TPUT 10 20;  $ e“EXIT”;}
       LM = 6
    MENU(){每个$(seq 0 $ LM);执行M $ {each};完成;}
     POS(){if [[$ cur == up]]; then((i  - )); fi
            if [[$ cur == dn]]; then((i ++)); fi
           如果[[$ i -lt 0]];则i = $ LM; fi
           如果[[$ i -gt $ LM]];则i = 0; fi;}
 REFRESH(){after = $((i + 1)); 之前= $(第(i-1))
            if [[$ before -lt 0]];然后= $ LM; fi
            if [[$ after -gt $ LM]];然后= 0; fi
            if [[$ j -lt $ i]];然后是UNMARK; M $ before;否则UNMARK; M $ after; fi
            if [[$ after -eq 0]] ||  [$ before -eq $ LM];然后
           取消标记;  M $之前;  M $后;网络连接; J = $ I;取消标记; M $之前; M $后;}
    INIT(){R; HEAD; FOOT; MENU;}
      SC(){REFRESH; MARK; $ S; $ b; cur =`ARROW`;}
      ES(){MARK; $ e“ENTER =主菜单”; $ b;读取; INIT;}; INIT
  而[[“$ O”!=“”]]; 做案例$ i in
         0)S = M0; SC;如果[[$ cur ==“”]];那么R; $ e“\ n $(w)\ n”; ES; fi ;;
         1)S = M1; SC;如果[[$ cur ==“”]];则R; $ e“\ n $(ifconfig)\ n”; ES; fi ;;
         2)S = M2; SC;如果[[$ cur ==“”]];那么R; $ e“\ n $(df -h)\ n”; ES; fi ;;
         3)S = M3; SC;如果[[$ cur ==“”]];那么R; $ e“\ n $(route -n)\ n”; ES; fi ;;
         4)S = M4; SC;如果[[$ cur ==“”]];则R; $ e“\ n $(日期)\ n”; ES; fi ;;
         5)S = M5; SC;如果[[$ cur ==“”]];则R; $ e“\ n $($ e by oTo)\ n”; ES; fi ;;
         6)S = M6; SC;如果[[$ cur ==“”]];则R;退出0; fi ;;
  ESAC; POS;完成

我还有一个选项是这些答案的混合,但令人感到高兴的是你只需要按一个键然后由于-n选项的读取而继续脚本。 在这个例子中,我们提示关闭,重新启动或者简单地使用ANS作为我们的变量退出scrit并且用户只需要按E,R或S.我还将默认设置为exit,因此如果按下enter,则脚本将退出。

 read -n 1 -p“你要退出,重新启动还是关机?(E / r / s)”ans;

 case $ ans in
     [R | R)
         sudo reboot ;;
     S | S)
         sudo poweroff ;;
     *)
        出口;;
 ESAC

在serverfault中已经回答了同样的问题。 那里的解决方案使用whiptail 。

假设您要使用普通shell脚本菜单(没有精美的UI),请查看http://www.tldp.org/LDP/abs/html/testbranch.html中的菜单示例。