Bash if: условная логика в Bash-скриптах

Быстрые ссылки
- Что такое условное выполнение?
- Простой пример if
- Конструкция elif
- Варианты условных тестов
- Вложенные if
- Когда использовать case вместо if
Краткое содержание
Конструкция if в Bash позволяет задавать условные выражения в формате if then fi. Добавление elif даёт дополнительные проверки, а else — обработку случая, когда ни одно условие не выполнено. Условные ветвления необходимы для скриптов любой практической сложности.
Важно: условные выражения — это способ задать вопрос скрипту и получить разные ответы в виде разных блоков кода.
Что такое условное выполнение?
Условное выполнение — это возможность программы менять поток выполнения в зависимости от истинности выражения. В Bash это обычно делается с помощью if-оператора. Простая мысль: если условие истинно, выполнить этот блок, иначе — выполнить другой.
Условие может проверять:
- значение переменной;
- наличие файла или каталога;
- сравнение строк или чисел;
- результат команды (код возврата).
Условная логика даёт программам гибкость: без неё скрипт выполняет только одну последовательность действий и не может адаптироваться к реальным условиям.
Простой пример if
Классическая форма простейшего if:
if [ this-condition-is-true ]
then
execute-these-statements
fiЕсли условие истинно, выполняется блок после then. Часто запись выглядит компактнее:
if [ this-condition-is-true ]; then
execute-these-statements
fiНесколько практических замечаний:
ifзавершается ключевым словомfi.- Между
[и условием и между условием и]должны быть пробелы. - Если
thenв той же строке, используйте;после].
Добавим else, чтобы обработать ложный случай:
if [ this-condition-is-true ]; then
execute-these-statements
else
execute-these-statements-instead
fiПример с проверкой возраста клиента (файл if-age.sh):
#!/bin/bash
customer_age=25
if [ $customer_age -ge 21 ]; then
echo 'Проходите.'
else
echo 'Вам нельзя входить.'
fiСделайте файл исполняемым:
chmod +x if-age.sh
./if-age.shЕсли заменить customer_age=18 и запустить снова, выполнится ветка else.
Конструкция elif
elif добавляет промежуточные проверки — их может быть сколько угодно. Они проверяются по порядку; при первом истинном условии выполняется соответствующий блок, остальные игнорируются. Если ни одно из условий не истинно и есть else, выполняется он.
Пример: проверка чётности числа (if-even.sh):
#!/bin/bash
echo -n 'Введите число: '
read number
if [ $number -eq 0 ]; then
echo 'Вы ввели ноль. Ноль — чётное число.'
elif [ $(($number % 2)) -eq 0 ]; then
echo "Вы ввели $number. Это чётное число."
else
echo "Вы ввели $number. Это нечётное число."
fiДля запуска:
chmod +x if-even.sh
./if-even.sh
Варианты условных тестов
Запись [ ... ] — это сокращение для программы test. Поэтому доступны все операции test.
Наиболее часто используемые тесты:
! expression— истинно, если выражение ложно.-n string— истинно, если длина строки > 0.-z string— истинно, если строка пустая.string1 = string2— истинно, если строки идентичны (символ за символом).string1 != string2— истинно, если строки различаются.integer1 -eq integer2— числовое равенство.integer1 -gt integer2— числовая операция: больше.integer1 -lt integer2— числовая операция: меньше.-d directory— существует каталог.-e file— существует файл.-s file— файл существует и его размер > 0.-r file— файл существует и доступен для чтения.-w file— файл существует и доступен для записи.-x file— файл существует и доступен для выполнения.
Важно понимать разницу между = и -eq: первая сравнивает как строки, вторая — как числа. Пример:
test 1 = 001
echo $? # вернёт 1 — ложь (строки разные)
test 1 -eq 001
echo $? # вернёт 0 — истина (числа равны)
Для шаблонного соответствия используйте двойные скобки [[ ]] — внутри них доступны шаблоны и несколько дополнительных возможностей:
#!/bin/bash
if [[ $USER == *ve ]]; then
echo "Привет, $USER"
else
echo "$USER не оканчивается на 've'"
fi[[ ]] защищает от некоторых неожиданностей, связанных с разбиением полей и подстановкой имен файлов (word splitting и pathname expansion).
Вложенные if
Можно вкладывать if внутрь другого if. Это допустимо, но ухудшает читабельность при глубине больше 2–3 уровней. Если вы оказались в глубокой вложенности, подумайте о реструктуризации логики (функции, case, таблицы соответствия).
Пример: определение рабочего времени магазина (if-shop.sh):
#!/bin/bash
# получить день недели числом 1..7 (1 — понедельник)
day=$(date +"%u")
if [ $day -le 6 ]; then
# магазин открыт
if [ $day -eq 3 ]; then
# среда — сокращённый день
echo 'По средам открыты только утром.'
else
echo 'Мы открыты весь день.'
fi
else
# воскресенье — выходной
echo 'Воскресенье — выходной.'
fiЗапускайте и тестируйте, меняя системное время или сами значения переменной day.

Совет: для сложной логики вместо глубокой вложенности используйте ранний выход из функции/скрипта (guard clauses) или перевод условий в отдельные функции.
Когда использовать case вместо if
if — универсальный инструмент, но не всегда оптимален. Если у вас большая ветвящаяся логика по значению одной переменной, case часто проще и читабельнее.
Пример шаблона case:
case $var in
pattern1)
commands ;;
pattern2)
commands ;;
*)
default_commands ;;
esaccase хорош для сопоставления строк по шаблону, if удобен для числовых и булевых проверок, проверки прав доступа, результатов команд и комбинаций условий.
Альтернативные подходы и когда if не подходит
- Для множественного сопоставления по одному значению — используйте
case. - Для простых бинарных решений можно использовать логические операторы
&&и||для компактного кода:command && echo 'OK' || echo 'ERROR'. - Для проверки набора условий удобна таблица соответствий (ассоциативный массив): ключ → обработчик.
- Для потоковой обработки большого объёма данных чаще применяют фильтрацию с помощью внешних инструментов (
awk,sed) вместо вложенныхif.
Примеры неудачного применения if:
- Глубокая вложенность >3 уровней; код становится нечитаемым.
- Повторяющиеся условия по одной и той же переменной;
caseкомпактнее. - Слишком много текстовых сравнений, где лучше применить регулярные выражения.
Ментальные модели и эвристики
- «Проверяй по одному факту»: каждая ветка
ifдолжна решать один аспект логики. - «Ранний выход»: если условие делает дальнейшую работу ненужной, заверши функцию сразу.
- «Сначала плохие сценарии»: сначала обрабатывайте ошибки и исключения, потом основной путь.
Эти правила улучшают читабельность и тестируемость.
Справочник и краткая памятка (Cheat sheet)
- Синтаксис:
if [ condition ]; then
commands
elif [ condition2 ]; then
commands
else
commands
fi- Используйте
[[ ]]для шаблонов и безопасных выражений. - Числовые сравнения:
-eq,-ne,-gt,-ge,-lt,-le. - Строковые сравнения:
=,!=,-z,-n. - Проверки файлов:
-e,-f,-d,-r,-w,-x,-s. - Получение кода возврата последней команды:
$?. - Проверка результата команды непосредственно в if:
if command; then ... fi(истина при коде возврата 0).
Шаблоны и сниппеты
Проверка существования файла:
if [ -e /path/to/file ]; then
echo 'Файл существует'
else
echo 'Файла нет'
fiПроверка строки на пустоту:
if [ -z "$var" ]; then
echo 'Пусто'
fiКомпактная запись через логические операторы:
command && echo 'Успех' || echo 'Неудача'Но будьте осторожны: в сложных случаях &&/|| могут вести себя не так, как ожидалось, если команды внутри возвращают разные коды выхода.
Проверки и критерии приёмки
- Скрипт корректно обрабатывает все ожидаемые входные данные.
- Для каждой ветки
ifесть тесты: позитивные и негативные сценарии. - Нет вложенности более трёх уровней без необходимости.
- Для пользовательских сообщений используются понятные тексты; внутренняя логика вынесена в функции.
Минимальные тесты для примеров выше:
if-age.sh: проверка для age=25 и age=18.if-even.sh: проверки для 0, чётного и нечётного числа.if-shop.sh: проверка для weekday, wednesday, sunday.
Рольные чек-листы
Разработчик:
- Явно обрабатывать ошибки ввода.
- Вынести повторяющуюся логику в функции.
- Добавить комментарии и пример запуска.
Системный администратор:
- Проверить права на выполнение скрипта (
chmod +x). - Проверить, что скрипт вызывается с нужной оболочкой (shebang).
Тестировщик:
- Подготовить набор входных значений, покрывающих все ветви.
- Автоматизировать запуск и сравнение вывода.
Диаграмма принятия решения (Mermaid)
flowchart TD
A[Есть ли несколько совпадающих значений одной переменной?] -->|Да| B[Используйте case]
A -->|Нет| C[Нужно ли проверять права/файлы/возврат команд?]
C -->|Да| D[Используйте if с тестами '-e, -x, код возврата']
C -->|Нет| E[Нужно ли шаблонное соответствие?]
E -->|Да| F[Используйте [[ ]] для шаблонов]
E -->|Нет| G[Используйте простые if или логические операторы]Матрица сравнения: if vs case vs [[ ]]
- if: гибкость, подходит для числовых и булевых проверок, проверки кодов возврата.
- case: удобство при множественном сопоставлении по одному значению; улучшает читабельность.
- [[ ]]: расширенные проверки строк, шаблоны; более безопасно в сценариях с подстановкой.
Безопасность и права
- Всегда проверяйте пути и права доступа перед выполнением операций с файлами.
- Не доверяйте входным данным: экранируйте переменные, используйте кавычки при подстановке.
- Для операций от имени root явно документируйте причины повышения привилегий.
Важно: отсутствие кавычек вокруг переменных — частая причина ошибок и уязвимостей (word splitting, globbing).
Глоссарий (одной строкой)
- if: базовый оператор ветвления в Bash.
- then/else/elif/fi: ключевые слова для управления ветками.
- test/[]: утилита для проверки выражений.
- [[ ]]: расширённая версия тестовых скобок с поддержкой шаблонов.
Когда всё собрано: методика разработки
- Напишите минимальную проверку, которая решает основной кейс.
- Добавьте проверки ошибок и
else-ветки. - Покройте код тестами: позитив и негатив.
- Рефакторите: вынесите повторяющуюся логику в функции или выберите
case. - Проверьте поведение при некорректных входных данных.
Когда if не справляется — примеры
- Большой набор условий по одному параметру →
caseбудет понятнее. - Обработка совпадений по сложным регулярным шаблонам — лучше
grep/awkили[[ =~ ]]. - Очень производительные потоки данных — фильтруйте внешними утилитами.
Краткое резюме
if— основной инструмент условной логики в Bash.- Используйте
[[ ]]для шаблонов и безопасных строковых сравнений. elifиelseдают гибкость;caseупрощает множественное сопоставление.- Избегайте глубокой вложенности, экранируйте переменные и покрывайте тестами.
Важно: простая, тестируемая и читаемая логика всегда выигрывает у хитроумных кратких конструкций.