В Bash, как добавить «Вы уверены [Y / n]» в любую команду или псевдоним? - PullRequest
201 голосов
/ 12 июля 2010

В данном конкретном случае я бы хотел добавить подтверждение в Bash для

Are you sure? [Y/n]

для Mercurial hg push ssh://username@www.example.com//somepath/morepath, который на самом деле является псевдонимом. Есть ли стандартная команда, которую можно добавить к псевдониму для ее достижения?

Причина в том, что hg push и hg out могут звучать одинаково, и иногда, когда я хочу hgoutrepo, я могу случайно ввести hgpushrepo (оба являются псевдонимами).

Обновление: , если это может быть что-то вроде встроенной команды с другой командой, такой как: confirm && hg push ssh://..., что было бы здорово ... просто команда, которая может запросить yes или no и продолжить с остальными, если yes.

Ответы [ 16 ]

292 голосов
/ 13 июля 2010

Это более компактные и универсальные формы ответа Хэмиша .Они обрабатывают любую комбинацию букв верхнего и нижнего регистра:

read -r -p "Are you sure? [y/N] " response
case "$response" in
    [yY][eE][sS]|[yY]) 
        do_something
        ;;
    *)
        do_something_else
        ;;
esac

Или, для Bash> = версия 3.2:

read -r -p "Are you sure? [y/N] " response
if [[ "$response" =~ ^([yY][eE][sS]|[yY])+$ ]]
then
    do_something
else
    do_something_else
fi

Примечание. Если $response - пустая строка, онавыдаст ошибку.Чтобы исправить, просто добавьте кавычки: "$response".- Всегда используйте двойные кавычки в переменных, содержащих строки (например: предпочитайте использовать "$@" вместо $@).

Или Bash 4.x:

read -r -p "Are you sure? [y/N] " response
response=${response,,}    # tolower
if [[ "$response" =~ ^(yes|y)$ ]]
...

Редактировать:

В ответ на ваши изменения вы можете создать и использовать команду confirm на основе первой версии в моем ответе (она будет работать аналогично двум другим):

confirm() {
    # call with a prompt string or use a default
    read -r -p "${1:-Are you sure? [y/N]} " response
    case "$response" in
        [yY][eE][sS]|[yY]) 
            true
            ;;
        *)
            false
            ;;
    esac
}

Чтобы использовать эту функцию:

confirm && hg push ssh://..

или

confirm "Would you really like to do a push?" && hg push ssh://..
19 голосов
/ 13 июля 2010

Вот примерно фрагмент, который вы хотите. Позвольте мне узнать, как передать аргументы.

read -p "Are you sure you want to continue? <y/N> " prompt
if [[ $prompt == "y" || $prompt == "Y" || $prompt == "yes" || $prompt == "Yes" ]]
then
  # /1176784/kak-peredat-parametry-drugoi-komande-v-skripte-bash
else
  exit 0
fi

Остерегайтесь yes | command name here:)

11 голосов
/ 13 июля 2010

Чтобы избежать явной проверки этих вариантов 'yes', вы можете использовать оператор регулярного выражения bash '= ~' с регулярным выражением:

read -p "Are you sure you want to continue? <y/N> " prompt
if [[ $prompt =~ [yY](es)* ]]
then
(etc...)

Это проверяет, начинается ли пользовательский ввод с 'y' или 'Y' и сопровождается нулем или более 'es'.

10 голосов
/ 22 сентября 2015

Подтверждения легко обойти с помощью возврата каретки, и я считаю полезным постоянно запрашивать действительный ввод.

Вот функция, облегчающая эту задачу. «неверный ввод» отображается красным, если Y | N не получено, и пользователю снова предлагается запрос.

prompt_confirm() {
  while true; do
    read -r -n 1 -p "${1:-Continue?} [y/n]: " REPLY
    case $REPLY in
      [yY]) echo ; return 0 ;;
      [nN]) echo ; return 1 ;;
      *) printf " \033[31m %s \n\033[0m" "invalid input"
    esac 
  done  
}

# example usage
prompt_confirm "Overwrite File?" || exit 0

Вы можете изменить приглашение по умолчанию, передав аргумент

4 голосов
/ 04 августа 2010

Это может быть взлом:

как в вопросе Является ли "xargs -p" в Unix / Bash хорошим способом запроса подтверждения перед выполнением любой команды?

мы можем использовать xargs для выполнения работы:

echo ssh://username@www.example.com//somepath/morepath | xargs -p hg push

конечно, это будет установлен как псевдоним, как hgpushrepo

Пример:

$ echo foo | xargs -p ls -l
ls -l foo?...y
-rw-r--r--  1 mikelee    staff  0 Nov 23 10:38 foo

$ echo foo | xargs -p ls -l
ls -l foo?...n

$
3 голосов
/ 14 июля 2010
read -r -p "Are you sure? [Y/n]" response
  response=${response,,} # tolower
  if [[ $response =~ ^(yes|y| ) ]] || [[ -z $response ]]; then
      your-action-here
  fi
3 голосов
/ 13 июля 2010

Добавьте следующее в ваш файл / etc / bashrc.Этот сценарий добавляет резидентную «функцию» вместо псевдонима «подтверждение».


function confirm( )
{
#alert the user what they are about to do.
echo "About to $@....";
#confirm with the user
read -r -p "Are you sure? [Y/n]" response
case "$response" in
    [yY][eE][sS]|[yY]) 
              #if yes, then execute the passed parameters
               "$@"
               ;;
    *)
              #Otherwise exit...
              echo "ciao..."
              exit
              ;;
esac
}
2 голосов
/ 13 сентября 2016

Ну, вот моя версия confirm, модифицированная от версии Джеймса:

function confirm() {
  local response msg="${1:-Are you sure} (y/[n])? "; shift
  read -r $* -p "$msg" response || echo
  case "$response" in
  [yY][eE][sS]|[yY]) return 0 ;;
  *) return 1 ;;
  esac
}

Эти изменения:

  1. используйте local, чтобы предотвратить совпадение имен переменных
  2. read используйте $2 $3 ... для управления его действием, поэтому вы можете использовать -n и -t
  3. если read завершается неудачно, echo перевод строки для красоты
  4. my Git on Windows имеет только bash-3.1 и не имеет true или false, поэтому используйте return. Конечно, это также совместимо с bash-4.4 (текущим в Git для Windows).
  5. используйте IPython-стиль "(y / [n])", чтобы четко указать, что "n" является значением по умолчанию.
1 голос
/ 28 июня 2018

Не нужно нажимать клавишу ввода

Вот более длинный, но многократно используемый и модульный подход:

  • Возвращает 0 = да и 1 = нет
  • Не нужно нажимать клавишу ввода - достаточно одного символа
  • Можно нажать , введите , чтобы принять выбор по умолчанию
  • Можно отключить выбор по умолчанию, чтобы принудительно сделать выбор
  • Работаеткак для zsh, так и для bash.

Значение по умолчанию "no" при нажатии enter

Обратите внимание, что N пишется с заглавной буквы.Здесь нажимается ввод, принимая значение по умолчанию:

$ confirm "Show dangerous command" && echo "rm *"
Show dangerous command [y/N]?

Также обратите внимание, что [y/N]? был добавлен автоматически.По умолчанию «нет» принимается, поэтому ничего не отображается.

Повторно запрашивать, пока не будет дан правильный ответ:

$ confirm "Show dangerous command" && echo "rm *"
Show dangerous command [y/N]? X
Show dangerous command [y/N]? y
rm *

По умолчанию «да», когданажатие enter

Обратите внимание, что Y пишется с заглавной буквы:

$ confirm_yes "Show dangerous command" && echo "rm *"
Show dangerous command [Y/n]?
rm *

Выше я только что нажал enter, поэтому команда запустилась.

Нет значения по умолчанию введите - требуется y или n

$ get_yes_keypress "Here you cannot press enter. Do you like this"
Here you cannot press enter. Do you like this [y/n]? k
Here you cannot press enter. Do you like this [y/n]?
Here you cannot press enter. Do you like this [y/n]? n
$ echo $?
1

Здесь 1 или false было возвращено.Обратите внимание, что заглавные буквы в [y/n]?

Code

# Read a single char from /dev/tty, prompting with "$*"
# Note: pressing enter will return a null string. Perhaps a version terminated with X and then remove it in caller?
# See https://unix.stackexchange.com/a/367880/143394 for dealing with multi-byte, etc.
function get_keypress {
  local REPLY IFS=
  >/dev/tty printf '%s' "$*"
  [[ $ZSH_VERSION ]] && read -rk1  # Use -u0 to read from STDIN
  # See https://unix.stackexchange.com/q/383197/143394 regarding '\n' -> ''
  [[ $BASH_VERSION ]] && </dev/tty read -rn1
  printf '%s' "$REPLY"
}

# Get a y/n from the user, return yes=0, no=1 enter=$2
# Prompt using $1.
# If set, return $2 on pressing enter, useful for cancel or defualting
function get_yes_keypress {
  local prompt="${1:-Are you sure} [y/n]? "
  local enter_return=$2
  local REPLY
  # [[ ! $prompt ]] && prompt="[y/n]? "
  while REPLY=$(get_keypress "$prompt"); do
    [[ $REPLY ]] && printf '\n' # $REPLY blank if user presses enter
    case "$REPLY" in
      Y|y)  return 0;;
      N|n)  return 1;;
      '')   [[ $enter_return ]] && return "$enter_return"
    esac
  done
}

# Credit: http://unix.stackexchange.com/a/14444/143394
# Prompt to confirm, defaulting to NO on <enter>
# Usage: confirm "Dangerous. Are you sure?" && rm *
function confirm {
  local prompt="${*:-Are you sure} [y/N]? "
  get_yes_keypress "$prompt" 1
}    

# Prompt to confirm, defaulting to YES on <enter>
function confirm_yes {
  local prompt="${*:-Are you sure} [Y/n]? "
  get_yes_keypress "$prompt" 0
}
1 голос
/ 11 апреля 2018

Это может быть немного слишком коротким, но для моего личного использования он прекрасно работает

read -n 1 -p "Push master upstream? [Y/n] " reply; 
if [ "$reply" != "" ]; then echo; fi
if [ "$reply" = "${reply#[Nn]}" ]; then
    git push upstream master
fi

read -n 1 просто читает один символ.Не нужно нажимать ввод.Если это не «n» или «N», предполагается, что это «Y».Простое нажатие клавиши ввода также означает Y.

(что касается реального вопроса: создайте этот сценарий bash и измените псевдоним так, чтобы он указывал на этот сценарий вместо того, на что он указывал ранее)

...