В Bash, как добавить "вы уверены [Y / n]" в любую команду или псевдоним?


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

Are you sure? [Y/n]

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

причина в том, что hg push и hg out может звук, похожий и иногда, когда я хочу!--4-->, Я могу случайно ввести hgpushrepo (оба являются псевдонимами).

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

16 178

16 ответов:

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

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". - Всегда используйте двойные кавычки в переменных, содержащих строки (например: prefer to use "$@" вместо $@).

Или, Баш 4.x:

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

Edit:

в ответ на ваше редактирование, вот как вы бы создать и использовать 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://..

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

read -p "Are you sure you want to continue? <y/N> " prompt
if [[ $prompt == "y" || $prompt == "Y" || $prompt == "yes" || $prompt == "Yes" ]]
then
  # http://stackoverflow.com/questions/1537673/how-do-i-forward-parameters-to-other-command-in-bash-script
else
  exit 0
fi

следи за yes | command name here :)

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

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

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

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

вот функция, чтобы сделать это легко. "недопустимый ввод" отображается красным цветом, если 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 " 3[31m %s \n3[0m" "invalid input"
    esac 
  done  
}

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

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

это может быть Хак:

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

можно использовать 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

$

добавьте в файл /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
}
read -r -p "Are you sure? [Y/n]" response
  response=${response,,} # tolower
  if [[ $response =~ ^(yes|y| ) ]] || [[ -z $response ]]; then
      your-action-here
  fi

Ну, вот моя версия 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 использовать ... для управления его действием, так что вы можете использовать -n и -t
  3. если read завершается неудачно, echo линия подачи для красоты
  4. мой Git on Windows только bash-3.1 и нет true или false, так что используйте return вместо. Конечно, это также совместимо с bash-4.4 (текущий в Git для Windows).
  5. используйте стиль IPython " (y / [n])", чтобы четко указать, что "n" является значением по умолчанию.

поздно к игре, но я создал еще один вариант confirm функции предыдущих ответов:

confirm ()
{
    read -r -p "$(echo $@) ? [y/N] " YESNO

    if [ "$YESNO" != "y" ]; then
        echo >&2 "Aborting"
        exit 1
    fi

    CMD=""
    shift

    while [ -n "" ]; do
        echo -en ""
        shift
    done | xargs -0 "$CMD" || exit $?
}

использовать:

confirm your_command

характеристики:

  • выводит команду как часть приглашения
  • передает Аргументы с помощью разделителя NULL
  • сохраняет состояние выхода вашей команды

ошибки:

  • echo -en работает с bash но может потерпеть неудачу в вашем оболочка
  • может произойти сбой, если аргументы мешают echo или xargs
  • миллион других ошибок, потому что сценарий оболочки трудно

попробуйте

 #!/bin/bash
 pause ()
 {
 REPLY=Y
 while [ "$REPLY" == "Y" ] || [ "$REPLY" != "y" ]
 do
  echo -e "\t\tPress 'y' to continue\t\t\tPress 'n' to quit"
  read -n1 -s
      case "$REPLY" in
      "n")  exit                      ;;
      "N")  echo "case sensitive!!"   ;; 
      "y")  clear                     ;;
      "Y")  echo "case sensitive!!"   ;;
      * )  echo "$REPLY is Invalid Option"     ;;
 esac
 done
 }
 pause
 echo "Hi"

не требуется нажимать enter

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

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

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

отметим, что N С большой буквы. Здесь нажать enter, по умолчанию:

$ 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 is с большой буквы:

$ 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]?

код

# 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=
# Prompt using .
# If set, return  on pressing enter, useful for cancel or defualting
function get_yes_keypress {
  local prompt="${1:-Are you sure} [y/n]? "
  local enter_return=
  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
}

Это не совсем "просить да или нет", а просто взломать: псевдоним hg push ... не hgpushrepo но

Не то же самое, но идея все равно работает.

#!/bin/bash  
i='y'  
while [ ${i:0:1} != n ]  
do  
    # Command(s)  
    read -p " Again? Y/n " i  
    [[ ${#i} -eq 0 ]] && i='y'  
done  

выход:
Опять? Y/n N
Опять? Г/н что-нибудь
Опять? Y / n 7
Опять? Y/n &
Опять? Y/n nsijf
$

теперь только проверяет 1-й символ $я читал.

ниже код сочетает в себе две вещи

  1. shopt-s nocasematch, который будет заботиться о нечувствительном к регистру

  2. и если условие, которое будет принимать оба входа либо вы проходите да, да, да, y.

    shopt-s nocasematch

    Если [[ sed-4.2.2.$LINE = ~ (yes / y)$ ]]

    затем выход 0

    fi

вот мое решение, которое использует локализованное регулярное выражение. Поэтому в немецком языке также "j "для" Ja " будет интерпретироваться как да.

первый аргумент-это вопрос, если второй аргумент "y", то да будет ответом по умолчанию, иначе нет будет ответом по умолчанию. Возвращаемое значение равно 0, если ответ был "да" и 1, если ответ был "нет".

function shure(){
    if [ $# -gt 1 ] && [[ "" =~ ^[yY]*$ ]] ; then
        arg="[Y/n]"
        reg=$(locale noexpr)
        default=(0 1)
    else
        arg="[y/N]"
        reg=$(locale yesexpr)
        default=(1 0)
    fi
    read -p " ${arg}? : " answer
    [[ "$answer" =~ $reg ]] && return ${default[1]} || return ${default[0]}
}

вот основное использование

# basic example default is no
shure "question message" && echo "answer yes" || echo "answer no"
# print "question message [y/N]? : "

# basic example default set to yes
shure "question message" y && echo "answer yes" || echo "answer no"
# print "question message [Y/n]? : "

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

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

The read -n 1 просто читает один символ. Если это не строчная буква "n", предполагается, что это "Y".

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