Як в Bash додати "Ви впевнені [Y / n]" до будь-якої команди чи псевдоніму?


228

У цьому конкретному випадку я хочу додати підтвердження в Bash for

Ти впевнений? [Y / n]

для Mercurial's hg push ssh://username@www.example.com//somepath/morepath, що насправді є псевдонімом. Чи є стандартна команда, яку можна додати до псевдоніма для її досягнення?

Причина полягає в тому, що hg pushі hg outможе здаватися подібним , а іноді , коли я хочу hgoutrepo, я можу accidentlly типу hgpushrepo(обидва є псевдонімами).

Оновлення: якщо це може бути щось на зразок вбудованої команди з іншою командою, наприклад: confirm && hg push ssh://...це було б чудово ... просто команда, яка може попросити yesабо noпродовжити з іншим, якщо yes.


1
Ви, ймовірно, захочете використовувати функцію замість псевдоніму. З 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:)


13

Підтвердження легко обминати поверненням перевезення, і мені здається корисним постійно підказувати дійсні дані.

Ось функція полегшити це. "Недійсний ввід" з'являється червоним кольором, якщо 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

Щоб уникнути явної перевірки цих варіантів "так", ви можете використовувати оператор регулярних виразів bash '= ~' з регулярним виразом:

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

Це перевіряє, чи починається введення користувачем з «у» або «Y» і супроводжується нулем або більше 's.


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Просто читає один символ. Не потрібно натискати Enter. Якщо це не 'n' або 'N', передбачається, що це 'Y'. Просто натискання клавіші Enter означає і 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величина з великим капіталом. Тут натискається клавіша 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великої літери:

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

Вище я просто натиснув клавішу enter, тому команда бігла.

Не встановлено за замовчуванням 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  

Вихід:
Знову? З / п N
Знову? Y / n
Знову щось ? З / п 7
Знову? Y / n &
Знову? Д / п nsijf
$

Тепер перевіряється лише перший символ $ i прочитаний.


0

Нижче код поєднує дві речі

  1. shopt -s nocasematch, який піклується про нечутливий випадок

  2. і якщо умова, яка прийме обидва вхідні дані, ви передасте так, так, так, так.

    shopt -s nocasematch

    якщо [[sed-4.2.2. $ LINE = ~ (так | 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.