Bash'te, herhangi bir komuta veya takma ada “Y / n] olduğundan emin misiniz?


228

Bu özel durumda, Bash'te bir onaylama eklemek istiyorum

Emin misiniz? [E / N]

hg push ssh://username@www.example.com//somepath/morepathaslında bir takma ad olan Mercurial için . Bunun için takma ada eklenebilecek standart bir komut var mı?

Nedeni hg pushve hg outbenzer gelebilir ve bazen istediğim zaman hgoutrepo, yanlışlıkla yazabilirim hgpushrepo(her ikisi de takma addır).

Güncelleme: başka bir komutla yerleşik bir komut gibi bir şey olabilir, örneğin: confirm && hg push ssh://...bu harika olurdu ... sadece bir yesveya sorabilir nove geri kalanına devam ederse bir komut yes.


1
Büyük olasılıkla takma ad yerine bir işlev kullanmak isteyeceksinizdir . Kimden info bash: "Neredeyse her amaç için kabuk işlevleri takma adlara tercih edilir."
sonraki duyuruya kadar duraklatıldı.

Gerçekten mi? ls -lveya gibi olanlar için bile rm -i?
nonopolarite

5
İçin neredeyse her değil, her . Bu arada, asla böyle bir şey yapmayın alias rm='rm -i'. Bir gün, en çok ihtiyaç duyduğunuzda, takma ad orada boom!olmayacak ve önemli bir şey kaybolacak.
sonraki duyuruya kadar duraklatıldı.

bekleyin, takma adınız rm -iyoksa, bir kabuk betiğine de güvenemezsiniz. Böylece her zaman yazabilirim rm -iher zaman?
nonopolarite

8
Alışkanlıklar hakkında . Önceki yorumumdakine benzer bir takma ad oluşturabilir rmve -idavranışı yazmayı ve beklemeyi alışkanlık haline getirebilirsiniz , o zaman bir gün takma ad orada değildir (bir nedenden dolayı ayarlanmaz veya ayarlanmaz veya farklı bir sistemdesiniz ) yazarsanız rm, onaylamadan hemen silinmeye başlar. Hata! Ancak, böyle bir takma ad yaptıysanız alias askrm='rm -i', "komut bulunamadı" hatası alacağınız için sorun olmaz.
sonraki duyuruya kadar duraklatıldı.

Yanıtlar:


332

Bunlar Hamish'in cevabının daha kompakt ve çok yönlü formlarıdır . Büyük ve küçük harflerin herhangi bir karışımını işlerler:

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

Veya Bash için> = sürüm 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

Not: $responseBoş bir dize ise hata verir. Düzeltme için, sadece tırnak işareti ekleyin: "$response". - Dizeleri içeren değişkenlerde her zaman çift tırnak kullanın (örneğin: "$@"bunun yerine kullanmayı tercih edin $@).

Veya Bash 4.x:

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

Düzenle:

Düzenlemenize yanıt olarak, cevabımdaki confirmilk sürüme dayanan bir komutu nasıl oluşturacağınız ve kullanacağınız (diğer ikisine benzer şekilde çalışır):

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
}

Bu işlevi kullanmak için:

confirm && hg push ssh://..

veya

confirm "Would you really like to do a push?" && hg push ssh://..

9
Aslında mevcut test için [Y / n] değil [y / N] olmalıdır.
Simon A. Eugster

not equal toİkinci örneği kontrol etmek istiyorsanız, $responsedeğişkeni yayınlamanız gerektiğini belirtmek gerekir . Ör: if [[ ! $response =~ ^([yY][eE][sS]|[yY])$ ]].
João Cunha

@ JoãoCunha: Normal ifade =~maç operatörü olduğu için bu "eşit değil" yerine "eşleşmez" olacaktır .
sonraki duyuruya kadar duraklatıldı.

@DennisWilliamson doğru, bunu demek istedim. Herhangi bir nedenden dolayı yorumumu düzenleyemiyorum.
João Cunha

6
Güzel genel amaçlı evet / hayır işlevi . güçlü bir istemi destekler ve isteğe bağlı olarak 'y' veya 'n' varsayılan yapar.
wkw

19

İşte kabaca istediğiniz bir pasaj. Argümanları nasıl ileteceğimi öğreneyim.

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

Dikkat edin yes | command name here:)


14

Onaylar satır başı ile kolayca atlanabilir ve geçerli girdi için sürekli bilgi istemenin yararlı olduğunu düşünüyorum.

İşte bunu kolaylaştıran bir işlev. Y | N alınmazsa ve kullanıcıya tekrar sorulursa "geçersiz giriş" kırmızı renkte görünür.

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

Bağımsız değişken ileterek varsayılan bilgi istemini değiştirebilirsiniz


12

Bu 'evet' varyantlarını açıkça kontrol etmekten kaçınmak için '= ~' bash normal ifade operatörünü normal bir ifade ile kullanabilirsiniz:

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

Bu, kullanıcı girişinin 'y' veya 'Y' ile başlayıp ardından sıfır veya daha fazla 's olup olmadığını test eder.


5

Bu bir saldırı olabilir:

söz konusu olduğu gibi Unix / Bash'te, "xargs -p" herhangi bir komutu çalıştırmadan önce onay istemek için iyi bir yöntem midir?

Kullandığımız yapabilirsiniz xargsişi yapmak için:

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

Tabii ki, bu bir takma ad olarak ayarlanacak, hgpushrepo

Misal:

$ 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 dosyanıza aşağıdakileri ekleyin. Bu komut dosyası, "onayla" adlı bir takma ad yerine yerleşik bir "işlev" ekler.


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
}

Güzel. Bununla birlikte, bazı küçük düzeltmeler: çift tırnak işaretleri koymalı $responseve $@yanlışları önlemek için bazı gereksiz noktalı virgüller vardır ve *durum çıkmamalı, geri dönmelidir.
Gordon Davisson

Açık olmak gerekirse, gereksiz olan bazı ifadelerin sonundaki tek noktalı virgül.
sonraki duyuruya kadar duraklatıldı.

4

Bu biraz fazla kısa olabilir, ancak kendi özel kullanımım için harika çalışıyor

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 1Sadece bir karakter okur. Enter tuşuna basmaya gerek yok. Eğer 'n' veya 'N' değilse, 'Y' olduğu varsayılır. Sadece enter tuşuna basmak Y demek.

(asıl soruya gelince: o bir bash betiğini hazırlayın ve takma adınızı daha önce işaret edilenin yerine bu betiğe işaret edecek şekilde değiştirin)


Kısa ve tatlı, tam ihtiyacım olan şey. Teşekkürler!
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

Yani boşluk karakteri evet demek?
Xen2050

'Evet veya y' dışındaki her şey işlemi onaylar, böylece haklısınız! @ xen2050
SergioAraujo

3

Hiçbir enter tuşuna gerek yok

İşte daha uzun ama yeniden kullanılabilir ve modüler bir yaklaşım:

  • İade 0= evet ve1 = hayır
  • Enter tuşuna basmaya gerek yok - sadece tek bir karakter
  • Basabilir enterVarsayılan seçimi kabul etmek için
  • Seçimi zorlamak için varsayılan seçimi devre dışı bırakabilir
  • Hem için çalışır zshve bash.

Enter tuşuna basıldığında varsayılan olarak "hayır"

Büyük Nharfle yazıldığını unutmayın. Burada enter tuşuna basılarak varsayılan değer kabul edilir:

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

Ayrıca, [y/N]? , otomatik olarak eklendiğini . Varsayılan "hayır" kabul edilir, bu nedenle hiçbir şey yankılanmaz.

Geçerli bir yanıt verilene kadar yeniden yönlendirin:

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

Enter tuşuna basıldığında varsayılan olarak "evet"

Büyük Yharfle yazıldığını unutmayın:

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

Yukarıda, enter tuşuna bastım, bu yüzden komut koştu.

Varsayılan olarak açık değil enter- zorunlu yveyan

$ 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

Burada 1ya da yanlış döndürüldü. Hiçbir büyük harf kullanımına dikkat edin[y/n]?

kod

# 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

İşte benim versiyonum, confirmJames'in birinden değiştirildi:

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
}

Bu değişiklikler:

  1. localdeğişken adlarının çarpışmasını önlemek için kullanın
  2. readkullanmak $2 $3 ...Eğer kullanabilir, böylece eylemini kontrol etmek -nve-t
  3. readçıkış başarısız olursa ,echo güzellik için bir satır besleme
  4. benim Git on Windowssadece vardır bash-3.1ve hayır trueya da false, yani kullanın return. Tabii ki, bu da bash-4.4 (Windows için Git'teki geçerli) ile uyumludur.
  5. "n" nin varsayılan olduğunu açıkça belirtmek için IPython stili "(y / [n])" kullanın.

2

Bu sürüm, birden fazla durumda olmasını sağlar yveya Y, nya daN

  1. İsteğe bağlı olarak: Onaylama sorusu sağlanana kadar soruyu tekrarlayın

  2. İsteğe bağlı: Diğer yanıtları yoksay

  3. İsteğe bağlı olarak: İsterseniz terminalden çıkın

    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=''
    }

Buna da dikkat edin: Bu işlevin son satırında REPLY değişkenini temizleyin. Aksi takdirde echo $REPLY, terminalinizi açana veya kapatana veya tekrar ayarlayana kadar hala ayarlandığını göreceksiniz.


1

Oyunun sonlarına doğru, ama confirmönceki cevapların işlevlerinin başka bir varyantını yarattım :

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

Kullanmak için:

confirm your_command

Özellikleri:

  • komutunuzu istemin bir parçası olarak yazdırır
  • bağımsız değişkenleri NULL sınırlayıcısını kullanarak geçirir
  • komutunuzun çıkış durumunu korur

Hatalar:

  • echo -enile çalışır bashancak kabuğunuzda başarısız olabilir
  • bağımsız değişkenler echoveyaxargs
  • Bir milyon milyon böcek daha çünkü kabuk komut dosyası oluşturmak zor

1

Deneyin,

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

Bu tam olarak bir "evet veya hayır istemek" değil, sadece bir kesmek: takma ad hg push ...değil hgpushrepoama hgpushrepoconfirmedpushher şeyi heceleyebildiğim zaman, sol beyin mantıklı bir seçim yaptı.


1
Ama TABanahtarı kullanacağını biliyorsun !
Hamish Grubijan

Tamam, doğru, ama en azından komuta bakacağım ve tuhaf olduğunu göreceğiz ve Enter'a
basmadan

0

Aynı değil, ama yine de işe yarayan bir fikir.

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

Çıktı:
Yine mi? E / H N
Yine mi? E / H
Tekrar Bir Şey Var mı? E / H 7
Yine mi? E / H ve
Tekrar? E / n nsijf
$

Şimdi sadece $ i okunan 1. karakterini kontrol eder.


0

Aşağıdaki kod iki şeyi birleştiriyor

  1. duyarsız davayı halledecek shopt -s nocasematch

  2. ve her iki girişi de kabul edecek bir durum ya evet'i geçerseniz, Evet, EVET, y.

    shopt -s nocasematch

    eğer [[sed-4.2.2. $ LINE = ~ (evet | y) $]]

    sonra 0'dan çık

    fi


0

İşte benim çözüm yerelleştirilmiş regex kullanarak. Yani Almanca'da "Ja" için "j" de evet olarak yorumlanır.

Birinci argüman soru, eğer ikinci argüman evet'ten "y" ise varsayılan cevap, aksi halde hayır varsayılan cevap olacaktır. Cevap "evet" ise dönüş değeri 0 ve cevap "hayır" ise 1'dir.

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]}
}

İşte temel bir kullanım

# 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]? : "
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.