В интерактивных скриптах Bash часто возникает необходимость задать пользователю простой вопрос «Да» или «Нет» и выполнить разные действия в зависимости от ответа. В этой статье мы разберём:
- Как правильно выводить запрос пользователю.
- Какие существуют способы чтения ответа (
read,select,case). - Как использовать условные операторы
if,elifиelseс несколькими условиями. - Как обрабатывать ввод без учёта регистра и с тайм‑аутом.
- Полезные приёмы для надёжного скрипта.
Базовый шаблон с read и if
Самый простой способ – вывести вопрос, считать ввод и сравнить его с ожидаемыми вариантами.
#!/bin/bash
echo -n "Продолжить работу? (да/нет): "
read reply
reply=${reply,,} # Bash 4+, меняет регистр на нижний
if "$reply" == "да" ; then
echo "Продолжаем..."
# Здесь размещаем код, который должен выполниться при «да»
elif "$reply" == "нет" ; then
echo "Останавливаемся."
exit 0
else
echo "Ответ не распознан. Пожалуйста, введите «да» или «нет»."
# Можно повторить запрос рекурсивно или выйти с ошибкой
exit 1
fi
В этом примере использованы:
- Оператор
[[ … ]]– более надёжный, чем[ … ], позволяет использовать логическое ИЛИ (||) и И (&&). - Синтаксис
${var,,}– преобразует строку к нижнему регистру, избавляя от необходимости писать несколько вариантов с разным регистром. - Блок
else– отлавливает любые неожиданные ответы.
Оператор elif для нескольких вариантов
Если требуется поддержать несколько вариантов «да» и «нет», удобно воспользоваться elif. Пример:
#!/bin/bash
read -p "Удалить все временные файлы? (y/n): " ans
ans=${ans,,}
if "$ans" == "y" ; then
echo "Файлы удаляются..."
rm -rf /tmp/*
elif "$ans" == "n" ; then
echo "Удаление отменено."
else
echo "Некорректный ввод."
exit 1
fi
Использование case вместо if
Для более читаемого кода при большом количестве вариантов можно применить case. Это особенно удобно, когда список возможных ответов длинный.
#!/bin/bash
read -p "Перезапустить сервис? (да/д/yes/y/нет/н/no/n): " answer
answer=${answer,,}
case "$answer" in
da|д|yes|y)
echo "Сервис перезапускается..."
systemctl restart myservice
;;
net|н|no|n)
echo "Перезапуск отменён."
;;
*)
echo "Неизвестный ответ: $answer"
exit 1
;;
esac
Логические операторы в условных выражениях
Иногда необходимо проверить несколько условий одновременно, например, существует ли файл config.cfg или default.cfg. Для этого используют логический оператор ИЛИ (||) внутри [[ … ]]:
if -f config.cfg ; then
echo "Конфигурационный файл найден."
else
echo "Нет ни одного из ожидаемых файлов."
fi
Аналогично, логическое И (&&) проверяет, что оба условия истинны:
if [[ -d /var/log && -w /var/log ]]; then
echo "Каталог /var/log существует и доступен для записи."
fi
Тайм‑аут для ввода пользователя
Иногда скрипт не должен ждать ввода бесконечно. Можно задать тайм‑аут с помощью ключа -t команды read:
#!/bin/bash
if read -t 10 -p "Продолжить? (да/нет): " reply; then
reply=${reply,,}
if [[ "$reply" == "да" ]]; then
echo "Продолжаем без задержек."
else
echo "Отмена."
exit 0
fi
else
echo -e "
Время ожидания истекло. Выходим."
exit 1
fi
Здесь -t 10 означает «ждать не более 10 секунд». Если пользователь не ввёл ничего, read завершается с ненулевым кодом возврата, и мы обрабатываем это в ветке else.
Полезные рекомендации
- Всегда проверяйте код возврата
read. Если пользователь нажал Ctrl+C или ввод прерван, скрипт может продолжить работу с неверными данными. - Нормализуйте ввод – перевод в нижний регистр (
${var,,}) и удаление пробелов (${var// /}) делают сравнение более надёжным. - Не забывайте про локаль. Если скрипт будет использовать русские ответы, убедитесь, что в системе установлена
LANG=ru_RU.UTF-8, иначе сравнение может работать некорректно. - Для сложных диалогов используйте
select– он автоматически формирует меню с нумерацией.
Пример с select
#!/bin/bash
PS3="Выберите действие (1‑Да, 2‑Нет): "
options=("Да" "Нет")
select opt in "${options[@]}"; do
case $REPLY in
1) echo "Вы выбрали Да"; break ;;
2) echo "Вы выбрали Нет"; break ;;
*) echo "Неправильный выбор." ;;
esac
done
Команда select выводит нумерованный список и ждёт ввода числа. Это удобно, когда вариантов несколько и нужно избежать опечаток.
Полный «шаблон» скрипта с вопросом «Да или нет»
Ниже представлена готовая заготовка, которую можно копировать в любой Bash‑скрипт и адаптировать под свои нужды.
#!/bin/bash
ask_yes_no {
local prompt="$1"
local default="$2" # "yes", "no" или "" (без значения по умолчанию)
local reply
# Формируем строку подсказки
if [[ "$default" == "yes" ]]; then
prompt="${prompt} [Y/n] "
elif [[ "$default" == "no" ]]; then
prompt="${prompt} [y/N] "
else
prompt="${prompt} [y/n] "
fi
while true; do
read -r -p "$prompt" reply
# Если пользователь просто нажал Enter, берём значение по умолчанию
if [[ -z "$reply" && -n "$default" ]]; then
reply="$default"
fi
reply=${reply,,} # нижний регистр
case "$reply" in
y|yes) return 0 ;; # Да
n|no) return 1 ;; # Нет
) echo "Пожалуйста, введите y/yes или n/no." ;;
esac
done
}
if ask_yes_no "Удалить все файлы в /tmp?" "no"; then
echo "Удаляем..."
rm -rf /tmp/
else
echo "Операция отменена."
fi
Эта функция:
- Поддерживает варианты ввода
y/yesиn/no(регистронезависимо). - Позволяет задать значение по умолчанию, которое будет использовано при пустом вводе.
- Возвращает статус 0 для «да» и 1 для «нет», что удобно использовать в условных конструкциях.
В Bash запрос «Да или нет» выглядит простым, но без правильного подхода скрипт может вести себя непредсказуемо:
- Не учитывайте регистр – пользователи могут написать
ДА,даилиY. - Обрабатывайте все возможные варианты, включая пустой ввод.
- Для более сложных проверок используйте логические операторы
||и&&внутри[[ … ]]. - Не забывайте о тайм‑ауте и о том, как правильно завершать скрипт с кодом возврата.
Следуя рекомендациям из этой статьи, вы сможете писать надёжные интерактивные скрипты, которые корректно реагируют на ответы пользователя «да» или «нет». Удачной разработки!