8

Как запросить подтверждение у пользователя в bash-скрипте?

1

Описание проблемы:

Я хочу добавить быстрый запрос "Вы уверены?" для подтверждения в начале потенциально опасного bash-скрипта. Какой самый простой и лучший способ сделать это?

Вижу, что на StackOverflow уже есть обсуждение, в котором предлагается несколько решений для создания запроса на ввод типа "Да/Нет/Отмена" в Linux shell-скриптах. Однако вопрос был закрыт 11 лет назад, и мне бы хотелось узнать актуальные методы или лучшие практики для реализации такой функции в современном контексте. Буду признателен за любые советы!

5 ответ(ов)

14

Вот перевод на русский язык в стиле ответа на 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]$ ]].

2

В приведённом коде используется конструкция case для обработки пользовательского ввода в bash. Это удобный и более читаемый способ, чем использовать несколько условных операторов if.

Вот как работает данный пример:

read -p "Continue (y/n)?" choice
case "$choice" in 
  y|Y ) echo "yes";;
  n|N ) echo "no";;
  * ) echo "invalid";;
esac

Преимущества использования case:

  1. Чище: Конструкция case делает код более компактным и легко читаемым, особенно когда нужно обрабатывать множетсво вариантов.

  2. Легче использовать условие "ИЛИ": В case можно объединить несколько условий в одну строку с помощью вертикальной черты |, что упрощает написание и понимание кода.

  3. Использование диапазонов символов: Например, можно использовать шаблон [yY][eE][sS], чтобы принять слово "yes" в любом случае, независимо от регистра его букв. Это упрощает работу с пользовательскими вводами, позволяя принимать их в любом регистре.

Такое решение особенно удобно, когда требуется обработка множественных вариантов ввода.

0

Попробуйте встроенную команду read в оболочке:

read -p "Продолжить (y/n)? " CONT
if [ "$CONT" = "y" ]; then
  echo "ура!"; 
else 
  echo "ууу!"; 
fi

Этот код запрашивает у пользователя, хочет ли он продолжить. Если пользователь вводит 'y', выводится "ура!"; в противном случае - "ууу!".

0

Вы можете использовать следующий код, чтобы получить 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. Если пользователь введет одну из этих опций, выполнение действия продолжится.

0

Вот функция, которую я использую:

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".
Чтобы ответить на вопрос, пожалуйста, войдите или зарегистрируйтесь