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


228

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

Ты уверен? [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.


1
Возможно, вы захотите использовать функцию вместо псевдонима. From info bash: «Практически для любых целей функции оболочки предпочтительнее псевдонимов».
Приостановлено до дальнейшего уведомления.

действительно? даже для таких как ls -lили rm -i?
неполярность

5
Для почти каждый, не каждый . Кстати, никогда не делай что-то подобное alias rm='rm -i'. Однажды, когда вам это нужно больше всего, псевдоним не будет там, и boom!что-то важное будет потеряно.
Приостановлено до дальнейшего уведомления.

подождите, если у вас нет псевдонима для rm -i, то вы также не можете рассчитывать на наличие сценария оболочки. Так вы всегда печатаете rm -iкаждый раз?
неполярность

8
Это о привычках . Вы можете создать псевдоним, подобный тому, что был в моем предыдущем комментарии, и иметь привычку печатать rmи ожидать -iповедение, тогда однажды псевдоним не будет найден (по какой-то причине он сбрасывается или не устанавливается, или вы работаете в другой системе). ) и вы печатаете, rmи он сразу же удаляет вещи без подтверждения. К сожалению! Тем не менее, если вы сделаете псевдоним, alias askrm='rm -i'то все будет в порядке, поскольку вы получите ошибку «команда не найдена».
Приостановлено до дальнейшего уведомления.

Ответы:


332

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

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://..

9
На самом деле это должно быть [y / N], а не [Y / n] для текущего теста.
Саймон Эугстер

Стоит отметить, что если вы хотите проверить not equal toвторой пример, вам следует привести $responseпеременную. Например: if [[ ! $response =~ ^([yY][eE][sS]|[yY])$ ]].
Жоау Кунья

@ JoãoCunha: Это будет "не совпадать", а не "не равно", так =~как это оператор совпадения с регулярным выражением.
Приостановлено до дальнейшего уведомления.

@ DennisWilliamson правильно, вот что я хотел сказать. Не могу редактировать мой комментарий по какой-то причине.
Жоао Кунья

6
Хорошая универсальная функция да / нет . поддерживает сильное приглашение, и, по желанию, по умолчанию используется значение y или n.
WKW

19

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

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:)


14

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

Вот функция, чтобы сделать это легко. «неверный ввод» отображается красным, если 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

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


12

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

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

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


5

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

как в вопросе В 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

$

4

Добавьте следующее в ваш файл / 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
}

Ницца. Некоторые незначительные исправления: вы должны поместить двойные кавычки $responseи, $@чтобы избежать ошибок, есть лишние точки с запятой, и *условие должно возвращаться, а не выходить.
Гордон Дэвиссон

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

4

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

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 и измените псевдоним так, чтобы он указывал на этот сценарий, а не на то, на что он указывал ранее)


Коротко и сладко, как раз то, что мне было нужно. Спасибо!
Raymo111

3
read -r -p "Are you sure? [Y/n]" response
  response=${response,,} # tolower
  if [[ $response =~ ^(yes|y| ) ]] || [[ -z $response ]]; then
      your-action-here
  fi

Значит, пробел означает да?
Xen2050

Все, кроме «да» или «да», подтвердят действие, поэтому вы правы! @ xen2050
SergioAraujo

3

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

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

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

По умолчанию «нет» при нажатии 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или ложь была возвращена. Обратите внимание, нет заглавных букв в[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=$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
}

2

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

2

Эта версия позволяет вам иметь более одного случая yили Y, nилиN

  1. Дополнительно: повторяйте вопрос до тех пор, пока не будет предоставлен вопрос для утверждения.

  2. По желанию: игнорировать любой другой ответ

  3. Опционально: выйдите из терминала, если хотите

    confirm() {
        echo -n "Continue? y or n? "
        read REPLY
        case $REPLY in
        [Yy]) echo 'yup y' ;; # you can change what you do here for instance
        [Nn]) break ;;        # exit case statement gracefully
        # Here are a few optional options to choose between
        # Any other answer:
    
        # 1. Repeat the question
        *) confirm ;;
    
        # 2. ignore
        # *) ;;
    
        # 3. Exit terminal
        # *) exit ;;
    
        esac
        # REPLY=''
    }

Обратите внимание и на это: в последней строке этой функции очистите переменную REPLY. В противном случае, если вы echo $REPLYувидите, что он все еще установлен, пока вы не откроете или не закроете свой терминал или не установите его снова.


1

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

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

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

    CMD="$1"
    shift

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

Чтобы использовать это:

confirm your_command

Особенности:

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

ошибки:

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

1

Пытаться,

 #!/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"

0

Это не просто «спрашивать да или нет», а просто взломать: псевдоним « hg push ...не к», hgpushrepoа к hgpushrepoconfirmedpushтому времени, когда я смогу разобрать все это, левый мозг сделал логичный выбор.


1
Но вы знаете, что вы будете использовать TABключ!
Хэмиш Грубиджан

хорошо, правда, но, по крайней мере, я посмотрю на команду и увижу, что это странно, и дважды подумаю, прежде чем нажать Enter
полярность

0

Не то же самое, но идея, которая работает в любом случае.

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

Вывод:
опять? Да / Нет
Снова? Да,
опять что-нибудь ? Да / Нет 7
Опять? Да и
снова? Да / нет nsijf
$

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


0

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

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

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

    shopt -s nocasematch

    if [[sed-4.2.2. $ LINE = ~ (yes | y) $]]

    затем выйдите из 0

    фи


0

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

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

function shure(){
    if [ $# -gt 1 ] && [[ "$2" =~ ^[yY]*$ ]] ; then
        arg="[Y/n]"
        reg=$(locale noexpr)
        default=(0 1)
    else
        arg="[y/N]"
        reg=$(locale yesexpr)
        default=(1 0)
    fi
    read -p "$1 ${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]? : "
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.