# Menus and Choices: case and select

case matches one value against a list of patterns and runs the lines for the first match, which suits a script's options and yes-or-no answers, and select turns a list of words into a numbered menu.

Apprentice · Unix · Linux · Updated November 10, 2026

## After this lesson you can

- Match one value against several patterns with case, using a pipe between patterns and \*) for anything else
- Show a numbered menu with select, use the chosen word from its variable, and end the menu with break

## Key takeaways

- case matches one value against patterns, top to bottom, and runs only the lines for the first match. esac, case backwards, ends it.
- | between patterns means or, *) matches anything else, and ;; ends each choice.
- case "$1" in with -h|--help) and --list) is the usual way a script handles its options.
- select shows the words after in as a numbered menu, puts the chosen word in its variable, and runs the lines between do and done.
- break ends a select menu after one choice. Without it, select asks again until you press Ctrl+D.

Call a pharmacy, and a recording says "press 1 for opening hours, 2 for prescriptions". Run almost any command with `--help`, and it explains itself. Both are menus: one choice, picked from a short list. Your backup script can have them too, a `--help` and a `--list` option, or a numbered list of files to pick from. You could write them with `if` and `elif`, but `[[ "$1" == ... ]]` on every line gets long and hard to read. Bash has a tidier way for each: `case` for matching one value against many, and `select` for a numbered menu. You'll find `case` at the top of most scripts administrators write, sorting out the options they were given.

The examples use the `smart-backup` folder and `backup.sh` from *Checking Before You Act: File Tests*: `cd ~/terminal-practice/smart-backup`.

## case: one value, many patterns

Picture a mail sorter reading each envelope's address and dropping it into the first slot that matches. `case` reads one value and tries a list of patterns, top to bottom. Try it at the prompt, with an answer someone might type:

```bash
answer=Y
case "$answer" in
  y|Y|yes|Yes) echo "Backing up." ;;
  n|N|no|No) echo "Nothing copied." ;;
  *) echo "Please answer yes or no." ;;
esac
```

```text
Backing up.
```

Read it piece by piece:

- `case "$answer" in` (read "in case the answer is…") names the value to match.
- Each choice is a pattern, a `)`, then its commands. `|` between patterns (read "or") lets one choice match several answers, so `Y` matches as well as `yes`.
- `;;` (read "end of choice") ends a choice's commands.
- `*)` matches anything at all, so as the last choice it catches every answer the others didn't. With `answer=maybe`, the script says "Please answer yes or no."
- `esac`, `case` backwards, ends the whole thing, the way `fi` ends `if`.

Only the first match runs. The patterns are the wildcards from *Wildcards: \*, ? and [ ]*, so `*.jpg)` would match every name ending in `.jpg`.

## Options for your script

Most scripts handle their options with `case "$1"`. Add these lines to `backup.sh`, right under its comment line:

```bash
case "$1" in
  -h|--help)
    echo "Usage: ./backup.sh FILE, or ./backup.sh --list"
    exit 0
    ;;
  --list)
    ls backup
    exit 0
    ;;
esac
```

```bash
./backup.sh --help
./backup.sh --list
./backup.sh essay.txt
```

```text
Usage: ./backup.sh FILE, or ./backup.sh --list
essay.txt  notes.txt
essay.txt hasn't changed since the last backup.
```

`exit 0` stops the script with "it worked", so the backup lines below never run for an option. There's no `*)` choice here on purpose: anything that isn't an option matches nothing, so `case` does nothing and the script carries on to back up the file. Adding a new option later means adding one more choice.

## select: a numbered menu in three lines

Sometimes picking from a list beats typing a name. `select` shows a list of words as a numbered menu and waits for a number. `PS3` holds the question it asks (without it, select asks `#?`). Type these lines at the prompt, then answer `4`:

```bash
PS3="Back up which file? "
select file in *.txt; do
  ./backup.sh "$file"
  break
done
```

```text
1) empty-draft.txt   3) notes.txt
2) essay.txt         4) reading-list.txt
Back up which file? 4
Copied reading-list.txt.
```

The words after `in` become the menu, here every `.txt` file in the folder. The word you pick goes into `file`, and the lines between `do` and `done` run with it. `select` is a loop, a set of lines that runs again and again (*For Every File: for Loops* teaches loops next chapter): without `break`, it would ask again after every choice, until you pressed Ctrl+D. A number that isn't on the menu leaves `file` empty, so `backup.sh` would answer "There's no  here.", with a gap where the name should be.

In a script on a Mac, `case` and `select` run in bash 5 like the rest of it; zsh has both too.

## Check yourself

2 questions to try on the lesson page.

## So what

`case` keeps a script's choices readable however many it grows, and `select` gives anyone who runs your script a menu instead of a blank prompt: two small steps that make a script feel like an application.

## Key terms

- [case Statement](https://www.ask-codey.com/glossary/case-statement)
- [select](https://www.ask-codey.com/glossary/select-unix)
- [Glob](https://www.ask-codey.com/glossary/glob)
- [Shell Script](https://www.ask-codey.com/glossary/shell-script)

## Cheat sheets

- [Menus and Choices: case and select](https://www.ask-codey.com/cheat-sheets/bash-case-and-select-cheat-sheet)

## Related

- [If This, Then That: if and \[\[ \]\]](https://www.ask-codey.com/lessons/bash-if-statements)
- [Checking Before You Act: File Tests](https://www.ask-codey.com/lessons/bash-file-tests)
- [Wildcards: \*, ? and \[ \]](https://www.ask-codey.com/lessons/bash-wildcards)

Source: https://www.ask-codey.com/lessons/bash-case-and-select
