Как запросить подтверждение у пользователя в bash-скрипте?
Описание проблемы:
Я хочу добавить быстрый запрос "Вы уверены?" для подтверждения в начале потенциально опасного bash-скрипта. Какой самый простой и лучший способ сделать это?
Вижу, что на StackOverflow уже есть обсуждение, в котором предлагается несколько решений для создания запроса на ввод типа "Да/Нет/Отмена" в Linux shell-скриптах. Однако вопрос был закрыт 11 лет назад, и мне бы хотелось узнать актуальные методы или лучшие практики для реализации такой функции в современном контексте. Буду признателен за любые советы!
5 ответ(ов)
Вот перевод на русский язык в стиле ответа на StackOverflow:
read -p "Вы уверены? " -n 1 -r
echo # (необязательно) переход на новую строку
if [[ $REPLY =~ ^[Yy]$ ]]
then
# выполните опасные действия
fi
Я учёл предложение levislevis85 (спасибо!) и добавил опцию -n
к команде read
, чтобы принять один символ без необходимости нажимать клавишу "Enter". Вы можете использовать один или оба этих подхода.
Также отрицательная форма может выглядеть так:
read -p "Вы уверены? " -n 1 -r
echo # (необязательно) переход на новую строку
if [[ ! $REPLY =~ ^[Yy]$ ]]
then
[[ "$0" = "$BASH_SOURCE" ]] && exit 1 || return 1 # обработка выхода из оболочки или функции, но без выхода из интерактивной оболочки
fi
Однако, как отметил Эрих, в некоторых случаях, таких как синтаксическая ошибка, вызванная запуском скрипта в неправильной оболочке, отрицательная форма может позволить скрипту продолжить выполнение "опасных действий". Режим неудачи должен способствовать наиболее безопасному исходу, поэтому следует использовать только первую, неотрицательную форму if
.
Пояснение:
Команда read
выводит подсказку (-p "подсказка"
), затем принимает один символ (-n 1
) и воспринимает обратные слэш-символы буквально (-r
) (в противном случае read
будет считать обратный слэш символом экранирования и будет ожидать второй символ). Переменной по умолчанию для хранения результата read
является $REPLY
, если вы не укажете имя, например так: read -p "моя подсказка" -n 1 -r my_var
.
Условный оператор if
использует регулярное выражение для проверки, соответствует ли символ в $REPLY
(оператор =~
) заглавной или строчной букве "Y". Регулярное выражение, использованное здесь, гласит: "строка, начинающаяся (^
) и состоящая исключительно из одного из символов в фигурных скобках ([Yy]
), заканчивается ($
)". Привязки (^
и $
) предотвращают сопоставление более длинных строк. В данном случае они помогают укрепить ограничение на один символ, установленное в команде read
.
Отрицательная форма использует логический оператор "не" (!
), чтобы сопоставить (=~
) любой символ, кроме "Y" или "y". Альтернативный способ выразить это менее читаем, и, на мой взгляд, не так явно демонстрирует намерение в данном контексте. Тем не менее, так это будет выглядеть: if [[ $REPLY =~ ^[^Yy]$ ]]
.
В приведённом коде используется конструкция case
для обработки пользовательского ввода в bash. Это удобный и более читаемый способ, чем использовать несколько условных операторов if
.
Вот как работает данный пример:
read -p "Continue (y/n)?" choice
case "$choice" in
y|Y ) echo "yes";;
n|N ) echo "no";;
* ) echo "invalid";;
esac
Преимущества использования case
:
Чище: Конструкция
case
делает код более компактным и легко читаемым, особенно когда нужно обрабатывать множетсво вариантов.Легче использовать условие "ИЛИ": В
case
можно объединить несколько условий в одну строку с помощью вертикальной черты|
, что упрощает написание и понимание кода.Использование диапазонов символов: Например, можно использовать шаблон
[yY][eE][sS]
, чтобы принять слово "yes" в любом случае, независимо от регистра его букв. Это упрощает работу с пользовательскими вводами, позволяя принимать их в любом регистре.
Такое решение особенно удобно, когда требуется обработка множественных вариантов ввода.
Попробуйте встроенную команду read
в оболочке:
read -p "Продолжить (y/n)? " CONT
if [ "$CONT" = "y" ]; then
echo "ура!";
else
echo "ууу!";
fi
Этот код запрашивает у пользователя, хочет ли он продолжить. Если пользователь вводит 'y', выводится "ура!"; в противном случае - "ууу!".
Вы можете использовать следующий код, чтобы получить y
, yes
или просто нажать Enter
для подтверждения:
Для bash:
read -r -p "Вы уверены? [Y/n]" response
response=${response,,} # перевод в нижний регистр
if [[ $response =~ ^(y| ) ]] || [[ -z $response ]]; then
your-action-here
fi
Если вы используете zsh, попробуйте следующий вариант:
read "response?Вы уверены? [Y/n] "
response=${response:l} # перевод в нижний регистр
if [[ $response =~ ^(y| ) ]] || [[ -z $response ]]; then
your-action-here
fi
В этом коде пользователь будет запрошен подтвердить действие, вводя y
, yes
или просто нажав Enter
. Если пользователь введет одну из этих опций, выполнение действия продолжится.
Вот функция, которую я использую:
function ask_yes_or_no() {
read -p "$1 ([y]es or [N]o): "
case $(echo $REPLY | tr '[A-Z]' '[a-z]') in
y|yes) echo "yes" ;;
*) echo "no" ;;
esac
}
И пример использования этой функции:
if [[ "no" == $(ask_yes_or_no "Вы уверены?") || \
"no" == $(ask_yes_or_no "Вы *действительно* уверены?") ]]
then
echo "Пропущено."
exit 0
fi
# Выполнить что-то действительно опасное...
- Вывод всегда "yes" или "no".
- По умолчанию возвращает "no".
- Все, что не является "y" или "yes", возвращает "no", так что это довольно безопасно для опасного bash-скрипта.
- И оно нечувствительно к регистру: "Y", "Yes" или "YES" будут работать как "yes".
Как изменить цвет вывода echo в Linux
Как сделать паузу в shell-скрипте на одну секунду перед продолжением?
Как работает "cat << EOF" в bash?
Как получить пароль из оболочки без вывода в терминал?
Сохранение многоточечных выводов в переменную Bash