Di Bash, bagaimana cara menambahkan "Apakah Anda yakin [Y / n]" ke perintah atau alias apa pun?

228

Dalam kasus khusus ini, saya ingin menambahkan konfirmasi di Bash untuk

Apakah kamu yakin [Y / n]

untuk Mercurial hg push ssh://[email protected]//somepath/morepath, yang sebenarnya adalah alias. Apakah ada perintah standar yang dapat ditambahkan ke alias untuk mencapainya?

Alasannya adalah bahwa hg pushdan hg outdapat terdengar mirip dan kadang-kadang ketika saya inginkan hgoutrepo, saya mungkin secara tidak sengaja mengetik hgpushrepo(keduanya alias).

Pembaruan: jika bisa berupa perintah bawaan dengan perintah lain, seperti: confirm && hg push ssh://...itu akan bagus ... hanya perintah yang bisa meminta yesatau nomelanjutkan dengan sisanya jika yes.

nonopolaritas
sumber
1
Anda mungkin ingin menggunakan fungsi alih-alih alias. Dari info bash: "Untuk hampir semua tujuan, fungsi shell lebih disukai daripada alias."
Dijeda sampai pemberitahuan lebih lanjut.
Betulkah? bahkan untuk yang seperti ls -latau rm -i?
nonopolaritas
5
Untuk hampir setiap, tidak setiap . Omong-omong, jangan pernah melakukan hal seperti itu alias rm='rm -i'. Suatu hari, ketika Anda sangat membutuhkannya, alias tidak akan ada di sana dan boom!sesuatu yang penting akan hilang.
Dijeda sampai pemberitahuan lebih lanjut.
tunggu, jika Anda tidak memiliki alias untuk rm -i, maka Anda tidak dapat mengandalkan memiliki skrip shell juga. Jadi, apakah Anda selalu mengetik rm -isetiap waktu?
nonopolaritas
8
Ini tentang kebiasaan . Anda dapat membuat alias seperti yang ada di komentar saya sebelumnya dan terbiasa mengetik rmdan mengharapkan -iperilaku, lalu suatu hari alias tidak ada di sana (untuk beberapa alasan itu menjadi tidak disetel atau tidak disetel atau Anda berada di sistem yang berbeda ) dan Anda mengetik rmdan langsung menghapus hal-hal tanpa konfirmasi. Ups! Namun, jika Anda melakukan alias seperti alias askrm='rm -i'maka Anda akan baik-baik saja, karena Anda akan mendapatkan kesalahan "perintah tidak ditemukan".
Dijeda sampai pemberitahuan lebih lanjut.

Jawaban:

332

Ini adalah bentuk jawaban Hamish yang lebih ringkas dan serbaguna . Mereka menangani campuran huruf besar dan kecil:

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

Atau, untuk Bash> = versi 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

Catatan: Jika $responsestring kosong, itu akan memberikan kesalahan. Untuk memperbaiki, cukup tambahkan tanda kutip: "$response". - Selalu gunakan tanda kutip ganda dalam variabel yang berisi string (mis: lebih suka menggunakan "$@"bukan $@).

Atau, Bash 4.x:

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

Edit:

Menanggapi hasil edit Anda, inilah cara Anda membuat dan menggunakan confirmperintah berdasarkan versi pertama dalam jawaban saya (ini akan bekerja sama dengan dua lainnya):

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
}

Untuk menggunakan fungsi ini:

confirm && hg push ssh://..

atau

confirm "Would you really like to do a push?" && hg push ssh://..
Dijeda sampai pemberitahuan lebih lanjut.
sumber
9
Sebenarnya seharusnya [y / N] dan bukan [Y / n] untuk tes saat ini.
Simon A. Eugster
Layak disebutkan bahwa jika Anda ingin memeriksa not equal tocontoh kedua, Anda harus menggunakan $responsevariabel. Misalnya: if [[ ! $response =~ ^([yY][eE][sS]|[yY])$ ]].
João Cunha
@ JoãoCunha: Itu akan menjadi "tidak cocok" daripada "tidak sama" karena =~adalah operator pertandingan regex.
Dijeda sampai pemberitahuan lebih lanjut.
@ DennisWilliamson benar, itulah yang saya coba maksudkan. Tidak dapat mengedit komentar saya karena alasan tertentu.
João Cunha
6
Tujuan umum bagus ya / tidak fungsi . mendukung prompt yang kuat, dan secara opsional menjadikan 'y' atau 'n' sebagai standar.
wkw
19

Ini kira-kira potongan yang Anda inginkan. Biarkan saya mencari tahu bagaimana meneruskan argumen.

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

Hati-hati yes | command name here:)

Hamish Grubijan
sumber
13

Konfirmasi mudah dilewati dengan carriage return, dan saya merasa berguna untuk terus meminta input yang valid.

Inilah fungsi untuk membuatnya mudah. "input tidak valid" muncul dengan warna merah jika Y | N tidak diterima, dan pengguna diminta lagi.

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

Anda dapat mengubah prompt default dengan memberikan argumen

briceburg
sumber
12

Untuk menghindari secara eksplisit memeriksa varian 'ya' ini, Anda dapat menggunakan operator ekspresi reguler bash '= ~' dengan ekspresi reguler:

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

Itu menguji apakah input pengguna dimulai dengan 'y' atau 'Y' dan diikuti oleh nol atau lebih dari itu.

pengguna389850
sumber
5

Ini mungkin hack:

seperti dalam pertanyaan Di Unix / Bash, apakah "xargs -p" cara yang baik untuk meminta konfirmasi sebelum menjalankan perintah?

kita dapat menggunakan xargsuntuk melakukan pekerjaan:

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

tentu saja, ini akan ditetapkan sebagai alias, seperti hgpushrepo

Contoh:

$ 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

$
nonopolaritas
sumber
4

Tambahkan berikut ini ke file / etc / bashrc Anda. Skrip ini menambahkan "fungsi" penduduk alih-alih alias yang disebut "konfirmasi".


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
}
MattyV
sumber
Bagus. Beberapa koreksi kecil: Anda harus menempatkan tanda kutip ganda di sekitar $responsedan $@untuk menghindari misparses, ada beberapa titik koma yang berlebihan, dan *kondisinya harus kembali, bukan keluar.
Gordon Davisson
Untuk lebih jelasnya, itu adalah titik koma tunggal di akhir beberapa pernyataan yang tidak perlu.
Dijeda sampai pemberitahuan lebih lanjut.
4

Ini mungkin agak terlalu pendek, tetapi untuk penggunaan pribadi saya, ini bekerja dengan baik

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

Itu read -n 1 hanya membaca satu karakter. Tidak perlu menekan enter. Jika bukan 'n' atau 'N', itu dianggap sebagai 'Y'. Hanya dengan menekan enter berarti Y juga.

(adapun pertanyaan sebenarnya: buat skrip bash dan ubah alias Anda untuk menunjuk ke skrip itu alih-alih apa yang ditunjuk sebelumnya)

Commonpike
sumber
Pendek dan manis, hanya apa yang saya butuhkan. Terima kasih!
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
SergioAraujo
sumber
Jadi karakter ruang berarti ya?
Xen2050
Semua kecuali 'ya atau y' akan mengkonfirmasi tindakan tersebut, jadi Anda benar! @ xen2050
SergioAraujo
3

Tidak perlu menekan enter

Inilah pendekatan yang lebih panjang, tetapi dapat digunakan kembali dan modular:

  • Pengembalian 0= ya dan 1= tidak
  • Tidak perlu menekan enter - hanya satu karakter
  • Dapat menekan enteruntuk menerima pilihan default
  • Dapat menonaktifkan pilihan default untuk memaksakan suatu pilihan
  • Bekerja untuk keduanya zshdan bash.

Standarnya menjadi "tidak" saat menekan enter

Perhatikan bahwa N huruf kapital. Sini masuk ditekan, menerima default:

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

Perhatikan juga, itu [y/N]? itu ditambahkan secara otomatis. Default "tidak" diterima, jadi tidak ada yang digaungkan.

Konfirmasikan kembali hingga respons yang valid diberikan:

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

Default ke "ya" saat menekan enter

Perhatikan bahwa Yhuruf kapital:

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

Di atas, saya hanya menekan enter, jadi perintahnya berlari.

Tidak ada default enter- memerlukan yataun

$ 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

Di sini, 1atau false dikembalikan. Perhatikan tidak ada huruf besar dalam[y/n]?

Kode

# 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
}
Tom Hale
sumber
2

Nah, ini versi saya confirm, dimodifikasi dari versi James:

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
}

Perubahan-perubahan ini adalah:

  1. gunakan localuntuk mencegah nama variabel bertabrakan
  2. readgunakan $2 $3 ...untuk mengontrol aksinya, jadi Anda dapat menggunakan -ndan-t
  3. jika readkeluar dengan tidak berhasil, echoberikan makan untuk kecantikan
  4. saya Git on Windowshanya punya bash-3.1dan tidak punya trueatau false, jadi gunakanreturn saja. Tentu saja, ini juga kompatibel dengan bash-4.4 (yang saat ini ada di Git untuk Windows).
  5. gunakan IPython-style "(y / [n])" untuk menunjukkan dengan jelas bahwa "n" adalah default.
Dahan Gong
sumber
2

Versi ini memungkinkan Anda memiliki lebih dari satu kasing yatau Y, natauN

  1. Opsional: Ulangi pertanyaan sampai pertanyaan yang disetujui diberikan

  2. Opsional: Abaikan jawaban lain

  3. Opsional: Keluar dari terminal jika Anda mau

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

Perhatikan ini juga: Pada baris terakhir dari fungsi ini, hapus variabel REPLY. Kalau tidak, jika Anda echo $REPLYakan melihatnya masih diatur sampai Anda membuka atau menutup terminal Anda atau mengaturnya lagi.

jasonleonhard
sumber
1

Terlambat dalam permainan, tetapi saya membuat varian lain dari confirmfungsi jawaban sebelumnya:

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

Untuk menggunakannya:

confirm your_command

Fitur:

  • mencetak perintah Anda sebagai bagian dari prompt
  • melewati argumen melalui penggunaan pembatas NULL
  • mempertahankan status keluar perintah Anda

Bug:

  • echo -enbekerja dengan bashtetapi mungkin gagal di shell Anda
  • mungkin gagal jika argumen mengganggu echoatauxargs
  • satu juta bug lainnya karena skrip shell sulit
thomas.me
sumber
1

Mencoba,

 #!/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"
Ranjithkumar T
sumber
0

Ini sebenarnya bukan "meminta ya atau tidak" tetapi hanya peretasan: alias hg push ...tidak untuk hgpushrepotetapi ke hgpushrepoconfirmedpushdan pada saat saya dapat menguraikan semuanya, otak kiri telah membuat pilihan yang logis.

nonopolaritas
sumber
1
Tetapi Anda tahu bahwa Anda akan menggunakan TABkuncinya!
Hamish Grubijan
ok, benar, tapi setidaknya saya akan melirik perintah dan melihatnya aneh dan berpikir dua kali sebelum menekan Enter
nonopolarity
0

Tidak sama, tetapi ide itu tetap berhasil.

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

Output:
Lagi? Y / t
lagi? Y / n Ada
Lagi Lagi? Y / n 7
Lagi? Y / t &
Lagi? Y / n nsijf
$

Sekarang hanya memeriksa karakter pertama dari $ i baca.

anonim
sumber
0

Kode di bawah ini menggabungkan dua hal

  1. shopt -s nocasematch yang akan menangani case-sensitive

  2. dan jika kondisi yang akan menerima kedua input baik Anda lulus ya, Ya, YA, y.

    shopt -s nocasematch

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

    lalu keluar 0

    fi

Shyam Gupta
sumber
0

Berikut adalah solusi saya yang menggunakan regex lokal. Jadi dalam bahasa Jerman juga "j" untuk "Ja" akan ditafsirkan sebagai ya.

Argumen pertama adalah pertanyaan, jika argumen kedua adalah "y" dari ya akan menjadi jawaban default, jika tidak, tidak akan menjadi jawaban default. Nilai baliknya adalah 0 jika jawabannya "ya" dan 1 jika jawabannya "tidak".

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

Ini adalah penggunaan dasar

# 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]? : "
David Boho
sumber