Ask Ubuntu is a question and answer site for Ubuntu users and developers. Join them; it only takes a minute:

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top

I'm creating a simple bash script and I want to create a select menu in it, like this:


echo "Choose your option:"

1) Option 1  
2) Option 2  
3) Option 3  
4) Quit  

And according to user's choice, I want different actions to be executed. I'm a bash shell scripting noob, I've searched the web for some answers, but got nothing really concrete.

share|improve this question
I'm pretty sure this would fit better on Stack Overflow. But just as a heads-up, bash has a select statement that will do this. See for example… – David Z Aug 8 '10 at 22:46
Another good place for this question would be – MountainX Jun 30 '13 at 8:46

14 Answers 14

# Bash Menu Script Example

PS3='Please enter your choice: '
options=("Option 1" "Option 2" "Option 3" "Quit")
select opt in "${options[@]}"
    case $opt in
        "Option 1")
            echo "you chose choice 1"
        "Option 2")
            echo "you chose choice 2"
        "Option 3")
            echo "you chose choice 3"
        *) echo invalid option;;

Add break statements wherever you need the select loop to exit. If a break is not performed, the select statement loops and the menu is re-displayed.

share|improve this answer
@Abdull: That's the intended behavior. The "Quit" option executes a break which breaks out of the select loop. You can add break anywhere you need it. The Bash manual states "The commands are executed after each selection until a break command is executed, at which point the select command completes." – Dennis Williamson Dec 7 '15 at 17:31

Not a new answer per se, but since there's no accepted answer yet, here are a few coding tips and tricks, for both select and 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;;



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.";;


Worth mentioning:

  • Both will loop until the user explicitly chooses Quit (or Cancel for zenity). This is a good approach for interactive script menus: after a choice is selected and action performed, menu is presented again for another choice. If choice is meant to be one-time only, just use break after esac (the zenity approach could be further reduced also)

  • Both case are index-based, rather than value-based. I think this is easier to code and maintain

  • Array is also used for zenity approach.

  • "Quit" option is not among the initial, original options. It is "added" when needed, so your array stay clean. Afterall, "Quit" is not needed for zenity anyway, user can just click "Cancel" (or close the window) to exit. Notice how both uses the same, untouched array of options.

  • PS3 and REPLY vars can not be renamed. select is hardcoded to use those. All other variables in script (opt, options, prompt, title) can have any names you want, provided you do the adjustments

share|improve this answer
Awesome explanation. Thank you. This question still ranks high on Google, so too bad it is closed. – MountainX Jun 30 '13 at 8:44

You can use this simple script for creating options

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;;
share|improve this answer

Since this is targeted at Ubuntu you should use whatever backend debconf is configured to use. You can find out the debconf backend with:

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

If it says "dialog" then it likely uses whiptail or dialog. On Lucid it's whiptail.

If that fails, use bash "select" as explained by Dennis Williamson.

share|improve this answer
This is probably overkill for that question, but +1 for mentioning whiptail and dialog! I wasnt aware of those commands... very sweet! – MestreLion Aug 5 '11 at 5:58

Using dialog, the command would look like this:

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"

enter image description here

Putting it in a script:


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)

case $CHOICE in
            echo "You chose Option 1"
            echo "You chose Option 2"
            echo "You chose Option 3"
share|improve this answer
    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}*********************************************${NORMAL}"
    echo -e "${MENU}**${NUMBER} 1)${MENU} Mount dropbox ${NORMAL}"
    echo -e "${MENU}**${NUMBER} 2)${MENU} Mount USB 500 Gig Drive ${NORMAL}"
    echo -e "${MENU}**${NUMBER} 3)${MENU} Restart Apache ${NORMAL}"
    echo -e "${MENU}**${NUMBER} 4)${MENU} ssh Frost TomCat Server ${NORMAL}"
    echo -e "${MENU}**${NUMBER} 5)${MENU} ${NORMAL}"
    echo -e "${MENU}*********************************************${NORMAL}"
    echo -e "${ENTER_LINE}Please enter a menu option and enter or ${RED_TEXT}enter to exit. ${NORMAL}"
    read opt
function option_picked() {
    COLOR='\033[01;31m' # bold red
    RESET='\033[00;00m' # normal white
    MESSAGE=${@:-"${RESET}Error: No message passed"}
    echo -e "${COLOR}${MESSAGE}${RESET}"

while [ opt != '' ]
    if [[ $opt = "" ]]; then 
        case $opt in
        1) clear;
        option_picked "Option 1 Picked";
        sudo mount /dev/sdh1 /mnt/DropBox/; #The 3 terabyte

        2) clear;
            option_picked "Option 2 Picked";
            sudo mount /dev/sdi1 /mnt/usbDrive; #The 500 gig drive

        3) clear;
            option_picked "Option 3 Picked";
        sudo service apache2 restart;

        4) clear;
            option_picked "Option 4 Picked";
        ssh lmesser@ -p 2010;



        option_picked "Pick an option from the menu";
share|improve this answer
I know this is old, but needs first line to read #!/bin/bash to compile. – JClar Dec 7 '14 at 12:15

I have used Zenity, which seems always there in Ubuntu, works very well and has many capabilities. This is a sketch of a possible menu:

#! /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";;
share|improve this answer
Oops! sorry about the appearance of this snippet, first time posting and seems have to turn HTML off perhaps – Mike Birchley May 5 '11 at 1:36
Better, turned 'code sample' on in editing, sorry about that – Mike Birchley May 5 '11 at 1:47

I have one more option that is a mixture of these answers but what makes it nice is that you only need to press one key and then the script continues thanks to the -n option of read. In this example, we are prompting to shutdown, reboot, or simply exit the scrit using ANS as our variable and the user only has to press E, R, or S. I also set the default to exit so if enter is pressed then the script will exit.

read -n 1 -p "Would you like to exit, reboot, or shutdown? (E/r/s) " ans;

case $ans in
        sudo reboot;;
        sudo poweroff;;
share|improve this answer

Bash fancy menu

Try it out first, then visit my page for detailed description ... No need for external libraries or programs like dialog or zenity ...

# by oToGamez

      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";};
           for each in $(seq 1 13);do
           $E "   x                                          x"
           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   ";}
   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;}
     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;;
share|improve this answer
This only works with bash, kinda cool. – Layton Everson Nov 17 '15 at 0:35
nice! "then visit my page for detailed description" is there link? – oak Dec 14 '15 at 13:36

There is already the same question in serverfault answered. The solution there uses whiptail.

share|improve this answer
Thanks, but as my script is for mainstream consumption, I don't want it to have any additional dependecies. But I'll bookmark that for use in the future, who knows. – Daniel Rodrigues Aug 8 '10 at 22:01

Have a look at whiptail (Ubuntu package) and the bash guide.

share|improve this answer
The so-called advanced bash scripting guide is not a good guide for learning bash. It teaches you to write bugs, not scripts. is suitable for beginners as well as more experienced users, and more importantly it teaches good practice (the only guide I know of). – geirha Feb 3 '11 at 23:33
geira, I made it 1/3 the way through and started finding errors. I think before recommending people use that guide and not the Advanced Bash Scripting Guide you should either correct the errors (I assume you have something to do with the guide since you're promoting it). This does actually work even if bad form - for file in ls; do rm "$file"; done – user97651 Oct 14 '12 at 18:29

Assuming you want to use a plain shell script menu (no fancy UI), check the menu example from .

share|improve this answer
As with much of the other snippets in the advanced bash-scripting guide, those snippets contain bugs and bad practice. – geirha Feb 3 '11 at 23:39
# "Two Words" Makes It Count As One Object, 
# But If It Is A Single Word,You Don't Need The ""
select choice in "Start Server" "Update Server" Exit
    case $REPLY in
            echo Start Server...

            echo Update Server...

            echo "Okay, Exiting..."
    break #stops From Re-Looping After Chooseing

share|improve this answer
This is conceptually and syntactically wrong.. – heemayl Aug 26 '15 at 19:00
select DRINK in tea water cafee juice appe all none
case $DRINK in

echo "Go to canteen"
echo "Available at home"
echo "ERROR: Invalid selection"

when i was type this commands,and must be enter text,i enter every text,shown me repetitive text "ERROR: Invalid selection". what am i do?

share|improve this answer

protected by heemayl Aug 26 '15 at 19:00

Thank you for your interest in this question. Because it has attracted low-quality or spam answers that had to be removed, posting an answer now requires 10 reputation on this site (the association bonus does not count).

Would you like to answer one of these unanswered questions instead?

Not the answer you're looking for? Browse other questions tagged or ask your own question.