In this week’s Bash Scripting Sunday, we’re diving into creating simple interactive menus in Bash.

If you’ve ever wanted to give your scripts a bit of user interactivity—like choosing from a list of options—you’ll love this one.


🧭 Why Use Menus?

Menus are great when:

  • You want to prompt the user for input from a list
  • You’re writing utility scripts with multiple actions
  • You want something more user-friendly than raw read input

🔧 The Basics: select and PS3

Bash comes with a built-in construct called select that makes menus easy.

Here’s the simplest form:

#!/usr/bin/env bash

PS3="Choose an option: "
options=("Start" "Stop" "Restart" "Quit")

select opt in "${options[@]}"; do
    case $opt in
        "Start")
            echo "Starting..."
            ;;
        "Stop")
            echo "Stopping..."
            ;;
        "Restart")
            echo "Restarting..."
            ;;
        "Quit")
            echo "Exiting."
            break
            ;;
        *) echo "Invalid option $REPLY";;
    esac
done

🧵 What’s Happening?

  • PS3 sets the prompt string.
  • select automatically prints a numbered list.
  • The user’s selection is stored in the variable $opt.
  • The number they typed is stored in $REPLY.

Try it out! It’ll look like this:

1) Start
2) Stop
3) Restart
4) Quit
Choose an option:

🧽 Cleaning It Up (Optional Enhancements)

Here are a few nice touches you can add:

1. Clear the screen before showing the menu

clear

Or use tput clear if you want to stay portable.

2. Repeat the menu until “Quit”

Wrap the select in a while true loop and break only on Quit:

while true; do
    select opt in "${options[@]}"; do
        case $opt in
            "Quit") break 2 ;;
            ...
        esac
    done
done

3. Add colours

Add colour using ANSI escape codes:

RED="\e[31m"
RESET="\e[0m"
echo -e "${RED}Error: Invalid choice${RESET}"

🧠 Tips & Gotchas

  • select works best in an interactive terminal – not ideal for scripts meant to run non-interactively.
  • Always validate the input inside the case, even if it looks correct.
  • select does not loop automatically – you control the loop.

🧪 Practical Use Case: Simple Admin Script

Here’s an example admin helper:

#!/usr/bin/env bash

PS3="Action: "
options=("Update System" "View Disk Usage" "Reboot" "Exit")

select opt in "${options[@]}"; do
    case $opt in
        "Update System")
            sudo apt update && sudo apt upgrade -y
            ;;
        "View Disk Usage")
            df -h
            ;;
        "Reboot")
            echo "Rebooting..."
            sudo reboot
            ;;
        "Exit")
            break
            ;;
        *) echo "Invalid option: $REPLY";;
    esac
done

🧵 Summary

  • select is a great way to build quick, interactive menus in Bash.
  • ✅ Use PS3 to customise the prompt.
  • ✅ Combine with loops and case to build functional CLI menus.
  • ✅ Great for small tools, helpers, or user-facing scripts.

Next week: We’ll cover how to safely handle temporary files in your scripts using traps and mktemp.

Until then, happy scripting! 🐚


📦 Bonus: Using dialog for Fancy Menus

If you want a more visual and interactive experience, dialog is a fantastic tool that provides full-screen menus, message boxes, and input prompts in the terminal.

Install it with:

sudo apt install dialog    # Debian/Ubuntu
sudo dnf install dialog    # Fedora
sudo pacman -S dialog      # Arch

Here’s how you can create a simple menu using dialog:

#!/usr/bin/env bash

HEIGHT=15
WIDTH=40
CHOICE_HEIGHT=4
TITLE="System Actions"
MENU="Choose one of the following:"

OPTIONS=(
  1 "Update System"
  2 "View Disk Usage"
  3 "Reboot"
  4 "Exit"
)

CHOICE=$(dialog --clear \
                --backtitle "Admin Menu" \
                --title "$TITLE" \
                --menu "$MENU" \
                $HEIGHT $WIDTH $CHOICE_HEIGHT \
                "${OPTIONS[@]}" \
                2>&1 >/dev/tty)

clear

case $CHOICE in
  1)
    sudo apt update && sudo apt upgrade -y
    ;;
  2)
    df -h
    ;;
  3)
    echo "Rebooting..."
    sudo reboot
    ;;
  4)
    echo "Exiting."
    ;;
esac

💡 Why Use dialog?

  • 📋 Easy to use with clear prompts
  • 🖥️ Feels more like a proper UI
  • ✅ Great for users unfamiliar with terminal prompts

⚠️ Just keep in mind:

  • It requires the dialog package to be installed.
  • Works best in a full-featured terminal (not ideal for limited environments).