Trong Bash, làm thế nào để thêm vào Bạn có chắc chắn [Y / n] về bất kỳ lệnh hoặc bí danh nào không?


228

Trong trường hợp cụ thể này, tôi muốn thêm một xác nhận trong Bash cho

Bạn có chắc không? [Y / n]

cho Mercurial hg push ssh://username@www.example.com//somepath/morepath, mà thực sự là một bí danh. Có một lệnh tiêu chuẩn có thể được thêm vào bí danh để đạt được nó?

Lý do là hg pushhg outcó thể nghe giống nhau và đôi khi khi tôi muốn hgoutrepo, tôi có thể vô tình gõ hgpushrepo(cả hai đều là bí danh).

Cập nhật: nếu nó có thể là một thứ gì đó giống như một lệnh tích hợp với một lệnh khác, chẳng hạn như: confirm && hg push ssh://...đó sẽ là điều tuyệt vời ... chỉ là một lệnh có thể yêu cầu yeshoặc notiếp tục với phần còn lại nếu yes.


1
Bạn có thể sẽ muốn sử dụng một chức năng thay vì bí danh. Từ info bash: "Đối với hầu hết mọi mục đích, các hàm shell được ưa thích hơn các bí danh."
Tạm dừng cho đến khi có thông báo mới.

có thật không? ngay cả đối với những người như ls -lhay rm -i?
phân cực

5
Đối với hầu hết mọi người, không phải mọi . Nhân tiện, không bao giờ làm một cái gì đó như thế alias rm='rm -i'. Một ngày nào đó, khi bạn cần nó nhất, bí danh sẽ không ở đó và boom!thứ gì đó quan trọng sẽ bị mất.
Tạm dừng cho đến khi có thông báo mới.

chờ đã, nếu bạn không có bí danh rm -i, thì bạn cũng không thể tin vào việc có tập lệnh shell. Vì vậy, bạn luôn luôn gõ rm -imỗi lần?
cực tính

8
Đó là về thói quen . Bạn có thể tạo một bí danh giống như trong nhận xét trước đây của tôi và có thói quen gõ rmvà mong đợi -ihành vi, sau đó một ngày bí danh không có ở đó (vì một số lý do, nó không được đặt hoặc không được đặt hoặc bạn đang ở trên một hệ thống khác ) và bạn gõ rmvà nó sẽ tiếp tục xóa nội dung mà không cần xác nhận. Giáo sư! Tuy nhiên, nếu bạn đã thực hiện một bí danh như thế alias askrm='rm -i'thì bạn sẽ ổn thôi, vì bạn sẽ gặp lỗi "không tìm thấy lệnh".
Tạm dừng cho đến khi có thông báo mới.

Câu trả lời:


332

Đây là những dạng câu trả lời nhỏ gọn và linh hoạt hơn của Hamish . Họ xử lý bất kỳ hỗn hợp của chữ in hoa và in thường:

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

Hoặc, đối với Bash> = phiên bản 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

Lưu ý: Nếu $responselà một chuỗi rỗng, nó sẽ báo lỗi. Để khắc phục, chỉ cần thêm dấu ngoặc kép : "$response". - Luôn sử dụng dấu ngoặc kép trong các biến chứa chuỗi (ví dụ: thích sử dụng "$@"thay thế $@).

Hoặc, Bash 4.x:

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

Biên tập:

Đáp lại chỉnh sửa của bạn, đây là cách bạn tạo và sử dụng confirmlệnh dựa trên phiên bản đầu tiên trong câu trả lời của tôi (nó sẽ hoạt động tương tự với hai phiên bản còn lại):

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
}

Để sử dụng chức năng này:

confirm && hg push ssh://..

hoặc là

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

9
Trên thực tế, nó phải là [y / N] chứ không phải [Y / n] cho thử nghiệm hiện tại.
Simon A. Eugster

Đáng nói là nếu bạn muốn kiểm tra not equal toví dụ thứ hai, bạn nên bỏ $responsebiến. Vd : if [[ ! $response =~ ^([yY][eE][sS]|[yY])$ ]].
João Cunha

@ JoãoCunha: Đó sẽ là "không khớp" thay vì "không bằng" vì =~là toán tử khớp regex.
Tạm dừng cho đến khi có thông báo mới.

@DennisWilliamson đúng, đó là những gì tôi đã cố gắng nói. Không thể chỉnh sửa nhận xét của tôi vì một số lý do.
João Cunha

6
Mục đích chung đẹp có / không có chức năng . hỗ trợ lời nhắc mạnh mẽ và tùy ý đặt mặc định 'y' hoặc 'n'.
wkw

19

Đây là khoảng một đoạn mà bạn muốn. Hãy để tôi tìm hiểu làm thế nào để chuyển tiếp các đối số.

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

Coi chừng yes | command name here:)


13

Xác nhận dễ dàng được bỏ qua với lợi nhuận vận chuyển và tôi thấy nó hữu ích để liên tục nhắc nhở cho đầu vào hợp lệ.

Đây là một chức năng để làm điều này dễ dàng. "đầu vào không hợp lệ" xuất hiện màu đỏ nếu không nhận được Y | N và người dùng được nhắc lại.

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

Bạn có thể thay đổi lời nhắc mặc định bằng cách chuyển một đối số


12

Để tránh kiểm tra rõ ràng các biến thể 'có' này, bạn có thể sử dụng toán tử biểu thức chính quy bash '= ~' với biểu thức chính quy:

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

Điều đó kiểm tra xem đầu vào của người dùng bắt đầu bằng 'y' hay 'Y' và được theo sau bằng 0 hoặc nhiều hơn.


5

Đây có thể là một hack:

như trong câu hỏi Trong Unix / Bash, "xargs -p" có phải là một cách hay để nhắc xác nhận trước khi chạy bất kỳ lệnh nào không?

chúng ta có thể sử dụng xargsđể thực hiện công việc:

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

Tất nhiên, điều này sẽ được đặt thành bí danh, như hgpushrepo

Thí dụ:

$ 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

Thêm phần sau vào tệp / etc / bashrc của bạn. Kịch bản lệnh này thêm một "chức năng" thường trú thay vì bí danh gọi là "xác nhận".


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
}

Đẹp. Tuy nhiên, một số sửa chữa nhỏ: bạn nên đặt dấu ngoặc kép xung quanh $response$@để tránh các lỗi sai, có một số dấu chấm phẩy thừa và *điều kiện sẽ quay trở lại, không thoát ra.
Gordon Davisson

Nói rõ hơn, đó là dấu chấm phẩy đơn ở cuối một số câu không cần thiết.
Tạm dừng cho đến khi có thông báo mới.

4

Điều này có thể hơi ngắn, nhưng đối với sử dụng riêng của tôi, nó hoạt động rất tốt

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

Chỉ read -n 1cần đọc một ký tự. Không cần nhấn enter. Nếu nó không phải là 'n' hoặc 'N', thì nó được coi là 'Y'. Chỉ cần nhấn enter cũng có nghĩa là Y.

(như đối với câu hỏi thực tế: làm cho đó là một tập lệnh bash và thay đổi bí danh của bạn để trỏ đến tập lệnh đó thay vì những gì được trỏ đến trước đó)


Ngắn và ngọt ngào, chỉ là những gì tôi cần. Cảm ơn!
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

Vì vậy, một nhân vật không gian có nghĩa là có?
Xen2050

Tất cả trừ 'có hoặc y' sẽ xác nhận hành động, vì vậy bạn đã đúng! @ xen2050
SergioAraujo

3

Không cần nhấn enter

Đây là một cách tiếp cận dài hơn, nhưng có thể tái sử dụng và mô-đun:

  • Trả về 0= có và 1= không
  • Không cần nhấn enter - chỉ một ký tự
  • Có thể nhấn enterđể chấp nhận lựa chọn mặc định
  • Có thể vô hiệu hóa lựa chọn mặc định để buộc lựa chọn
  • Hoạt động cho cả zshbash.

Mặc định là "không" khi nhấn enter

Lưu ý rằng đó Nlà thủ đô. Ở đây nhập được nhấn, chấp nhận mặc định:

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

Cũng lưu ý, điều đó [y/N]?đã được tự động thêm vào. "Không" mặc định được chấp nhận, vì vậy không có gì được lặp lại.

Nhắc lại cho đến khi phản hồi hợp lệ được đưa ra:

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

Mặc định là "có" khi nhấn enter

Lưu ý rằng Ychữ viết hoa:

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

Ở trên, tôi chỉ nhấn enter, nên lệnh chạy.

Không có mặc định trên enter- yêu cầu yhoặcn

$ 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

Ở đây, 1hoặc sai đã được trả lại. Lưu ý không viết hoa trong[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

Chà, đây là phiên bản của tôi confirm, được sửa đổi từ bản của 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
}

Những thay đổi này là:

  1. sử dụng localđể ngăn chặn các tên biến đổi va chạm
  2. readsử dụng $2 $3 ...để kiểm soát hành động của nó, vì vậy bạn có thể sử dụng -n-t
  3. Nếu readthoát không thành công, echomột nguồn cấp dữ liệu cho vẻ đẹp
  4. của tôi Git on Windowschỉ có bash-3.1và không có truehoặc false, vì vậy sử dụng returnthay thế. Tất nhiên, điều này cũng tương thích với bash-4.4 (phiên bản hiện tại trong Git cho Windows).
  5. sử dụng kiểu IPython "(y / [n])" để chỉ rõ rằng "n" là mặc định.

2

Phiên bản này cho phép bạn có nhiều hơn một trường hợp yhoặc Y, nhoặcN

  1. Tùy chọn: Lặp lại câu hỏi cho đến khi câu hỏi phê duyệt được cung cấp

  2. Tùy chọn: Bỏ qua bất kỳ câu trả lời khác

  3. Tùy chọn: Thoát khỏi thiết bị đầu cuối nếu bạn muố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=''
    }

Cũng lưu ý điều này: Trên dòng cuối cùng của chức năng này, hãy xóa biến REPLY. Mặt khác, nếu bạn echo $REPLYsẽ thấy nó vẫn được đặt cho đến khi bạn mở hoặc đóng thiết bị đầu cuối của bạn hoặc đặt lại.


1

Đến cuối trò chơi, nhưng tôi đã tạo ra một biến thể khác của các confirmchức năng của các câu trả lời trước:

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

Để dùng nó:

confirm your_command

Đặc trưng:

  • in lệnh của bạn như là một phần của dấu nhắc
  • chuyển các đối số thông qua việc sử dụng dấu phân cách NULL
  • duy trì trạng thái thoát lệnh của bạn

Lỗi:

  • echo -enhoạt động với bashnhưng có thể thất bại trong vỏ của bạn
  • có thể thất bại nếu các đối số can thiệp vào echohoặcxargs
  • hàng trăm lỗi khác vì kịch bản shell rất khó

1

Thử,

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

Đây không chính xác là "yêu cầu có hay không" mà chỉ là một hack: bí danh hg push ...không phải hgpushreponhưng đến hgpushrepoconfirmedpushlúc tôi có thể đánh vần toàn bộ, não trái đã đưa ra lựa chọn hợp lý.


1
Nhưng bạn biết rằng bạn sẽ sử dụng TABchìa khóa!
Hamish Grubijan

ok, đúng, nhưng ít nhất tôi sẽ liếc nhìn lệnh và thấy nó thật kỳ lạ và suy nghĩ kỹ trước khi nhấn Enter
nonopolarity

0

Không giống nhau, nhưng ý tưởng nào cũng hoạt động.

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

Đầu ra:
Một lần nữa? Y / n N
nữa không? Y / n gì
nữa không? Y / n 7
nữa không? Y / n &
Một lần nữa? Y / n nsijf
$

Bây giờ chỉ kiểm tra ký tự đầu tiên của $ i đọc.


0

Mã dưới đây được kết hợp hai điều

  1. shopt -s nocasematch sẽ chăm sóc trường hợp không nhạy cảm

  2. và nếu điều kiện sẽ chấp nhận cả hai đầu vào, bạn sẽ vượt qua có, Có, CÓ, y.

    shopt -s nocasematch

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

    sau đó thoát 0

    fi


0

Đây là giải pháp của tôi rằng sử dụng regex cục bộ. Vì vậy, trong tiếng Đức cũng "j" cho "Ja" sẽ được hiểu là có.

Đối số đầu tiên là câu hỏi, nếu đối số thứ hai là "y" hơn có thì sẽ là câu trả lời mặc định nếu không sẽ không phải là câu trả lời mặc định. Giá trị trả về là 0 nếu câu trả lời là "có" và 1 nếu câu trả lời là "không".

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

Đây là một cách sử dụng cơ bản

# 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]? : "
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.