Bash: оператор case … esac — руководство и примеры

Что такое оператор case и зачем он нужен
Оператор case в Bash — это конструкция для множественных ветвлений. По смыслу он соответствует switch/case в других языках и применяется, когда нужно проверить одно выражение на соответствие множеству образцов и вызвать разный код для каждого совпадения.
Кратко:
- case сравнивает одно значение с набором шаблонов (glob-паттернов) и выбирает первую подходящую ветку.
- Каждая ветка завершается последовательностью символов
;;. - Есть общий (catch-all) шаблон
*, который сработает, если остальные не подошли.
Преимущества использования case вместо if/elif:
- Читаемость при большом количестве вариантов.
- Удобная запись нескольких шаблонов для одной ветки через
|. - Поддерживает шаблоны вида
*,?,[a-z],pattern|otherи т. п.
Важно: case использует шаблоны (глоб-паттерны), а не регулярные выражения.
Простой рабочий пример
Определим скрипт test.sh:
#!/bin/bash
case "${1}" in
1) echo "Option was 1!";;
2) echo "Option was 2!";;
*) echo "Option was something else: '${1}'";;
esacСделайте файл исполняемым и запустите с разными аргументами:
chmod +x test.sh
./test.sh 1 # Option was 1!
./test.sh 2 # Option was 2!
./test.sh foo # Option was something else: 'foo'Разбор синтаксиса:
case "${1}" in— берём первый аргумент скрипта как выражение для сравнения.- Каждая ветка начинается с образца, затем
)и блок команд. - Ветку завершает
;;— это важно: одно;внутри case не достаточно.

Частая ошибка: пропущенные ;;
Если использовать только один ; или не закрыть ветку правильно, Bash выдаст синтаксическую ошибку. Например, этот код не скомпилируется:
case "${1}" in
1) echo "Option 1";
2) echo "Option 2";
esacНужно писать ;; в конце каждой ветки.

Альтернатива через if/elif — когда подходит, когда нет
Эквивалентный пример через if/elif:
#!/bin/bash
if [ "${1}" == "1" ]; then
echo "Option was 1!"
elif [ "${1}" == "2" ]; then
echo "Option was 2!"
else
echo "Option was something else: '${1}'"
fiЕсли вариантов немного или условия сложные логические выражения, if/elif тоже отлично подойдёт. Но при десятках вариантов и при использовании шаблонов (напр., *.txt или [0-9]*) case выглядит компактнее и яснее.

Расширяем пример: несколько шаблонов и вложенные case
Case позволяет указывать несколько шаблонов для одной ветки через |, а также вкладывать case внутри ветки:
#!/bin/bash
case "${1}" in
1|3)
echo "Option was 1 or 3"
;;
2|'a')
case "${1}" in
2) echo "Option was 2";;
'a') echo "Option was 'a'";;
esac
;;
*)
echo "Option was something else: '${1}'"
;;
esacОбратите внимание: вложенный case завершён esac, и после него при необходимости ставят ;; чтобы закрыть внешнюю ветку (в примере выше esac находится внутри внешней ветки, затем ;;).

Полезные шаблоны и приёмы
*— любой набор символов (включая пустую строку).?— ровно один любой символ.[abc]/[a-z]— любой символ из набора или диапазона.pattern1|pattern2— перечисление альтернатив.- Цитирование шаблонов: если шаблон содержит пробелы или метасимволы, экранируйте или берите в кавычки.
Пример: обработка расширения файла
#!/bin/bash
file="$1"
case "$file" in
*.sh) echo "Это shell-скрипт";;
*.py) echo "Это Python-скрипт";;
*.txt) echo "Это текстовый файл";;
*) echo "Неизвестный тип файла";;
esacМентальные модели и эвристики
- Представляйте case как таблицу соответствий: вход → шаблон → обработчик.
- Если у вас много литеральных вариантов — используйте case.
- Если нужны сложные логические выражения между несколькими переменными — if/elif может быть удобнее.
- Для сопоставления по расширению файлов и простых паттернов — case чаще всего быстрее по чтению.
Когда case не подходит (контрпримеры)
- Нужны сложные булевы выражения, зависящие от нескольких переменных одновременно.
- Нужно проверять числовые диапазоны с арифметическими условиями (лучше if с арифметикой или test).
- Нужна проверка по регулярному выражению PCRE — case использует glob-паттерны, а не полноценные регулярные выражения.
Альтернативные подходы
- if/elif — для условий, комбинирующих несколько проверок.
- assoc arrays (bash 4+) — когда нужно сопоставление ключ→значение, вместо ветвления.
- grep/awk/sed — для извлечения и проверки сложных шаблонов в строках.
Практическое руководство: чеклист перед использованием case
- Одна переменная/значение, по которому выполняется выбор.
- Большое количество дискретных вариантов или шаблонов.
- Не требуются регулярные выражения (glob-паттерны подходят).
- [ ] Каждая ветка завершается
;;. - [ ] Обработчик по умолчанию
*предусмотрен. - Убедитесь в корректном экранировании пробелов и специальных символов.
Критерии приёмки
- Скрипт корректно выбирает ветку для каждого из тестовых входов.
- Для неизвестного входа выполняется ветка
*. - Ни одна ветка не оставляет незавершённый
case(синтаксическая проверка). - Логирование/вывод понятен и информативен для отладки.
Тесты и контрольные случаи
- Входы с ожидаемыми буквальными значениями (“1”, “2”).
- Входы с шаблонными значениями (“file.sh”, “README.txt”).
- Пустой вход (никакой аргумент) — должен сработать
*. - Вложенные случаи: убедиться, что внешний и внутренний case корректно закрываются.
Мини-методология написания надёжного case
- Определите единственное выражение для проверки (переменная).
- Составьте список шаблонов в порядке убывания специфичности (специфичные — первыми).
- Добавьте обработчик по умолчанию
*в конце. - Для каждой ветки пишите краткие, атомарные команды; избегайте длинных логических блоков.
- Протестируйте все ветки и граничные случаи.
Роль-based checklist (разработчик / ревьюер)
Разработчик:
- Писать маленькие ветки с понятными сообщениями.
- Проверять обработку пустого аргумента.
- Документировать нестандартные шаблоны.
Ревьюер:
- Проверить наличие
;;в конце каждой ветки. - Убедиться, что вложенная логика правильно отделена и не ломает парсинг.
- Проверить экранирование переменных и кавычек.
Безопасность и кавычки
Всегда берите переменные в кавычки в выражении case: case "${var}" in — это защищает от разбиения по словам и специальных символов. Не подставляйте в шаблоны необработанные значения пользователей без валидации, особенно если от результата зависит выполнение команд в файловой системе.
Краткое сравнение: case vs if/elif
- Читаемость: при многих вариантов — case выигрывает.
- Гибкость: if/elif — подходит для сложных логических условий.
- Шаблоны: case поддерживает glob-паттерны прямо «из коробки».
Примеры расширенного использования
Обработка подкоманд (микто-CLI):
#!/bin/bash
cmd="$1"
shift
case "$cmd" in
start)
echo "Запуск сервиса"
# команды запуска
;;
stop)
echo "Остановка сервиса"
# команды остановки
;;
status)
echo "Статус сервиса"
;;
*)
echo "Неизвестная команда: $cmd"
echo "Использование: $0 {start|stop|status}"
;;
esacСоветы по читабельности
- Группируйте похожие шаблоны с помощью
|. - Используйте пустые строки между ветками для визуального разделения.
- Комментарии коротко объясняют нестандартные кейсы.
Глоссарий (одна строка на термин)
case — конструкция множественного ветвления в shell; pattern — glob-паттерн, используемый в case для сравнения; ;; — маркер окончания ветки case;
- — универсальный (catch-all) шаблон.
Резюме
Оператор case … esac в Bash — мощный и читабельный инструмент для выбора кода по множеству шаблонов. Он особенно хорош для обработки подкоманд, расширений файлов и любых случаев, где необходимо сопоставление единого входа со многими вариантами. Правильное использование ;;, | и шаблонов делает код устойчивым и понятным.
Небольшая шпаргалка: всегда кавычьте переменные в case, не забывайте ;;, используйте * для ветки по умолчанию и группируйте шаблоны через |.
Удачи и приятного кодинга!
Похожие материалы
RDP: полный гид по настройке и безопасности
Android как клавиатура и трекпад для Windows
Советы и приёмы для работы с PDF
Calibration в Lightroom Classic: как и когда использовать
Отключить Siri Suggestions на iPhone