A shell script can offer actions as numbered choices. Bash select displays those choices, reads a selection, and repeats the menu body until break ends the loop.
This piece explains how Bash select works and shows how to build a menu and check its response.
TL;DR: Build a menu with Bash select
Bash select prints numbered choices, reads a selection, and repeats its body until you break out of the loop.
- Set PS3 to label the prompt.
- Use case to handle each choice and a default branch.
- Use break for an exit choice.
What Is the select Loop in Bash?
The select compound command builds a numbered menu from words and runs a command list for each line of input. It belongs to Bash, so scripts that use it should name Bash in their shebang rather than assume every POSIX shell provides the construct.
Bash expands the words after in, displays each with a number, then reads a line using PS3 as the prompt. A matching number assigns the corresponding word to the menu variable, while REPLY keeps the input text. The body runs again after each choice unless a command such as break ends the loop.
The menu offers readable labels, and case maps them to actions.
How to Build a select Menu Step by Step
A small action menu needs a prompt, a list of labels, and a handler for every selection. Put the construct in a Bash script so its loop and exit behavior remain visible.
Step 1: Define the prompt and choices
Set PS3 before select and list the words users can choose. The example uses status, restart, and quit labels.
#!/usr/bin/env bash
PS3="Choose an action: "
select action in status restart quit; do
case $action in
status) printf 'Selected %s (option %s)\n' "$action" "$REPLY" ;;
restart) printf 'Selected %s (option %s)\n' "$action" "$REPLY" ;;
quit) printf 'Leaving menu.\n'; break ;;
*) printf 'Invalid option: %s\n' "$REPLY" ;;
esac
done
The menu variable contains the matched word, while REPLY retains the entered selection number. In a production script, replace the printf lines with the intended action and keep the default branch so unexpected input receives a response.
Step 2: Run the menu and inspect its response
Run the saved file with Bash and provide choices in order. The first input chooses restart, the second tests the default branch, and the third selects quit.
printf '2\n9\n3\n' | bash select_menu.sh
1) status
2) restart
3) quit
Choose an action: Selected restart (option 2)
Choose an action: Invalid option: 9
Choose an action: Leaving menu.

I ran this exact input stream and the menu handled all three inputs before ending with exit status 0. The valid choice did not end the loop by itself, so the quit branch needs break.
Common Problems with a Bash select Loop
The menu needs deliberate handling for input that does not match a numbered choice. In my run, entering 9 printed “Invalid option: 9,” left the menu variable unmatched, and returned to the prompt.
Handle invalid choices, blank input, and EOF
Use the case statement’s default branch for text or numbers outside the menu. Bash leaves the selected word unmatched and keeps the entered line in REPLY, so the script can report the input without treating it as a command.
A blank line displays the menu again without running the body. End-of-file behaves differently: select terminates with a nonzero status when its input closes. Check that status when a script receives redirected or piped input.
| Case | Symptom or behavior | Fix |
|---|---|---|
| Valid menu number | The menu variable receives its label | Dispatch the recognized label in a case branch |
| Unlisted text or number | No label matches. The input remains in REPLY | Use the default branch to reject or explain the input |
| Blank line | The menu and prompt appear again | Offer a separate numbered exit choice |
| End-of-file | select ends with nonzero status | Check status when input is redirected or piped |
| Using a menu label as a command | A label such as status does not run a command by itself | Map each known label to an explicit case action, and never evaluate arbitrary REPLY text |
| Automating file or stream input | select expects a menu number, not a record to process | Use a read loop for records or streamed lines |
| Nested loops | break exits only the innermost loop by default | Use a numbered break only when exiting multiple levels is intended |
Conclusion
Bash select supplies the numbered menu and repeated prompt, while your case branches define what each choice does. Keep REPLY available for validation and break for a deliberate exit.
For the authoritative behavior, see the Bash Reference Manual on conditional constructs. To compare this menu with iteration over a known list, see Bash for loops in shell scripts and the site’s shell scripting and cron guide.
FAQ
These answers cover the prompt, input variable, and menu exit behavior.
How do I change the Bash select prompt?
Set PS3 before the select command. Bash displays that prompt each time it asks for a choice.
What does REPLY contain in a select loop?
REPLY contains the line entered at the prompt. The menu variable contains the matching choice label, or an empty value for an invalid selection.
How do I exit a select loop?
Run break in the branch that should leave the menu. Without break, select prompts again after the branch finishes.
