How can I create a select menu in a shell script?

Solution 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

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.

In the third option, I included variables that are set by the select statement to demonstrate that you have access to those values. If you choose it, it will output:

you chose choice 3 which is Option 3

You can see that $REPLY contains the string you entered at the prompt. It is used as an index into the array ${options[@]} as if the array were 1 based. The variable $opt contains the string from that index in the array.

Note that the choices could be a simple list directly in the select statement like this:

select opt in foo bar baz 'multi word choice'

but you can't put such a list in a scalar variable because of the spaces in one of the choices.

You can also use file globbing if you are choosing among files:

select file in *.tar.gz

Solution 2:

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:

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

Solution 3:

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 1";;
    2) echo "You picked $opt which is option 2";;
    3) echo "You picked $opt which is option 3";;
    $((${#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

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

Solution 4:

You can use this simple script for creating options

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