ใน Bash วิธีเพิ่ม“ คุณแน่ใจ [Y / n]” ในคำสั่งหรือนามแฝงใด ๆ


228

ในกรณีนี้โดยเฉพาะฉันต้องการเพิ่มการยืนยันใน Bash สำหรับ

คุณแน่ใจไหม? [Y / N]

สำหรับ Mercurial's hg push ssh://username@www.example.com//somepath/morepathซึ่งจริงๆแล้วเป็นนามแฝง มีคำสั่งมาตรฐานที่สามารถเพิ่มในนามแฝงเพื่อให้บรรลุหรือไม่

เหตุผลก็คือhg pushและhg outสามารถฟังเหมือนกันและบางครั้งเมื่อฉันต้องการhgoutrepoฉันอาจพิมพ์โดยไม่ตั้งใจhgpushrepo(ทั้งคู่เป็นนามแฝง)

ปรับปรุง:ถ้ามันสามารถเป็นสิ่งที่ชอบในตัวคำสั่งที่มีคำสั่งอื่นเช่นconfirm && hg push ssh://...ที่ต้องการจะดี ... เพียงแค่คำสั่งที่สามารถขอได้yesหรือและดำเนินการกับส่วนที่เหลือถ้าnoyes


1
คุณอาจต้องการใช้ฟังก์ชั่นแทนนามแฝง จากinfo bash: "เกือบทุกวัตถุประสงค์ฟังก์ชั่นเชลล์เป็นที่ต้องการมากกว่าชื่อแทน"
หยุดชั่วคราวจนกว่าจะมีการแจ้งให้ทราบต่อไป

จริงๆ? แม้กระทั่งสำหรับคนที่ชอบls -lหรือrm -i?
nonopolarity

5
สำหรับเกือบทุกไม่ใช่ทุก โดยวิธีการที่ไม่เคยalias rm='rm -i'ทำสิ่งที่ชอบ วันหนึ่งเมื่อคุณต้องการมันมากที่สุดนามแฝงจะไม่อยู่ที่นั่นและboom!บางสิ่งที่สำคัญจะหายไป
หยุดชั่วคราวจนกว่าจะมีการแจ้งให้ทราบต่อไป

รอถ้าคุณไม่มีนามแฝงrm -iคุณก็ไม่สามารถคาดหวังได้ว่ามีสคริปต์เชลล์เช่นกัน ดังนั้นคุณพิมพ์rm -iทุกครั้งหรือไม่
nonopolarity

8
มันเป็นเรื่องของนิสัย คุณสามารถสร้างนามแฝงเช่นเดียวกับความคิดเห็นก่อนหน้าของฉันและอยู่ในนิสัยของการพิมพ์rmและคาดหวังว่า-iพฤติกรรมแล้ววันหนึ่งนามแฝงไม่ได้มี (ด้วยเหตุผลบางอย่างที่มันได้รับการตั้งค่าหรือไม่ได้ตั้งหรือคุณอยู่ในระบบที่แตกต่างกัน ) และคุณพิมพ์rmและมันไปข้างหน้าลบสิ่งโดยไม่ต้องยืนยันทันที อ๊ะ! อย่างไรก็ตามหากคุณทำนามแฝงเช่นalias askrm='rm -i'นั้นคุณจะไม่เป็นไรเนื่องจากคุณได้รับข้อผิดพลาด "ไม่พบคำสั่ง"
หยุดชั่วคราวจนกว่าจะมีการแจ้งให้ทราบต่อไป

คำตอบ:


332

นี่เป็นคำตอบของ Hamish ที่กะทัดรัดและหลากหลายกว่า พวกเขาจัดการกับส่วนผสมของตัวอักษรตัวใหญ่และตัวเล็ก:

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] สำหรับการทดสอบปัจจุบัน
Simon A. Eugster

เป็นมูลค่าการกล่าวขวัญว่าถ้าคุณต้องการตรวจสอบnot equal toในตัวอย่างที่สองคุณควรโยน$responseตัวแปร if [[ ! $response =~ ^([yY][eE][sS]|[yY])$ ]]เช่น:
João Cunha

@ JoãoCunha: นั่นจะเป็น "ไม่ตรงกัน" แทนที่จะเป็น "ไม่เท่ากัน" เนื่องจาก=~เป็นโอเปอเรเตอร์การจับคู่ regex
หยุดชั่วคราวจนกว่าจะมีการแจ้งให้ทราบต่อไป

@DennisWilliamson ถูกต้องนั่นคือสิ่งที่ฉันพยายามจะหมายถึง ไม่สามารถแก้ไขความคิดเห็นของฉันด้วยเหตุผลบางอย่าง
João Cunha

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' หรือ 'Y' และตามด้วยศูนย์หรือมากกว่านั้น


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และ$@เพื่อหลีกเลี่ยงการพิมพ์ผิดมีเซมิโคลอนซ้ำซ้อนบางส่วนและ*เงื่อนไขควรกลับคืนไม่ใช่ออก
Gordon Davisson

เพื่อให้ชัดเจนมันเป็นอัฒภาคเดี่ยวที่ส่วนท้ายของข้อความที่ไม่จำเป็น
หยุดชั่วคราวจนกว่าจะมีการแจ้งให้ทราบต่อไป

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 ด้วย

(สำหรับคำถามจริง: ทำให้เป็นสคริปต์ทุบตีและเปลี่ยนนามแฝงของคุณให้ชี้ไปที่สคริปต์นั้นแทนที่จะเป็นสิ่งที่ชี้ไปก่อนหน้านี้)


สั้นและหวานเพียงแค่สิ่งที่ฉันต้องการ ขอบคุณ!
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

ทั้งหมดยกเว้น 'ใช่หรือ y' จะยืนยันการกระทำดังนั้นคุณพูดถูก! @ xen2050
SergioAraujo

3

ไม่จำเป็นต้องกด Enter

ต่อไปนี้เป็นวิธีการที่ยาวกว่า แต่ใช้ซ้ำได้และแบบแยกส่วน

  • ส่งคืน0= ใช่และ1= ไม่
  • ไม่จำเป็นต้องกด Enter - เพียงตัวเดียว
  • สามารถกดenterเพื่อยอมรับตัวเลือกเริ่มต้น
  • สามารถปิดการใช้งานตัวเลือกเริ่มต้นเพื่อบังคับให้เลือก
  • ผลงานของทั้งสองและzshbash

เริ่มต้นที่ "ไม่" เมื่อกด 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 ดังนั้นคำสั่งจึงรัน

ไม่มีค่าเริ่มต้นใน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ดัดแปลงมาจาก James 'one:

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-style "(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
  • คงสถานะการออกของคำสั่งของคุณ

Bugs:

  • echo -enทำงานร่วมกับbashแต่อาจล้มเหลวในเปลือกของคุณ
  • อาจล้มเหลวหากมีข้อโต้แย้งขัดขวางechoหรือxargs
  • zillion บั๊กอื่น ๆ เพราะเชลล์สคริปต์ยาก

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กุญแจ!
Hamish Grubijan

ตกลงจริง แต่อย่างน้อยฉันจะมองไปที่คำสั่งและเห็นว่ามันเป็นเรื่องแปลกและคิดว่าสองครั้งก่อนที่จะกด Enter
nonopolarity

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  

เอาท์พุท:
อีกครั้ง? Y / n N
อีกครั้ง? Y / n มีอะไร
อีกไหม? Y / n 7
อีกครั้งเหรอ? Y / n &
อีกครั้ง? Y / n nsijf
$

ตอนนี้ตรวจสอบอักขระที่ 1 ของ $ i ที่อ่านแล้วเท่านั้น


0

รหัสด้านล่างคือการรวมสองสิ่ง

  1. shopt -s nocasematch ที่จะดูแลกรณีตาย

  2. และถ้าเงื่อนไขที่จะยอมรับทั้งอินพุตคุณก็ผ่านใช่, ใช่, ใช่

    shopt -s nocasematch

    ถ้า [[sed-4.2.2. $ LINE = ~ (ใช่ | y) $]]

    จากนั้นออกจาก 0

    Fi


0

นี่คือทางออกของฉันที่ใช้ regex แปล ดังนั้นในภาษาเยอรมัน "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]? : "
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.