Câu hỏi Làm thế nào để nhắc cho đầu vào Có / Không / Hủy trong tập lệnh shell Linux?


Tôi muốn tạm dừng đầu vào trong một kịch bản lệnh shell và nhắc người dùng lựa chọn. Câu hỏi loại 'Có, Không hoặc Hủy' tiêu chuẩn. Làm thế nào để thực hiện điều này trong một dấu nhắc bash điển hình?


1101
2017-10-22 17:03


gốc




Các câu trả lời:


Phương thức đơn giản nhất và rộng rãi nhất để có được đầu vào của người dùng tại dấu nhắc trình bao là read chỉ huy. Cách tốt nhất để minh họa cho việc sử dụng nó là một minh chứng đơn giản:

while true; do
    read -p "Do you wish to install this program?" yn
    case $yn in
        [Yy]* ) make install; break;;
        [Nn]* ) exit;;
        * ) echo "Please answer yes or no.";;
    esac
done

Một phương pháp khác, được chỉ ra bởi Steven Huwig, là của Bash select chỉ huy. Đây là ví dụ tương tự bằng cách sử dụng select:

echo "Do you wish to install this program?"
select yn in "Yes" "No"; do
    case $yn in
        Yes ) make install; break;;
        No ) exit;;
    esac
done

Với select bạn không cần phải khử trùng đầu vào - nó sẽ hiển thị các lựa chọn có sẵn và bạn nhập một số tương ứng với lựa chọn của bạn. Nó cũng tự động lặp lại, vì vậy không cần thiết while true lặp lại để thử lại nếu chúng cung cấp đầu vào không hợp lệ.

Ngoài ra, hãy kiểm tra câu trả lời xuất sắc bởi F. Hauri.


1272
2017-10-22 17:08



đọc -p "Bạn có muốn cài đặt chương trình này không?" - Steve Baker
Sử dụng Bash trong OS X Leopard, tôi đã thay đổi exit đến break để tiếp tục đóng tab khi tôi chọn 'không'. - Trey Piepmeier
@ Trey, bạn có thể muốn sử dụng returnthay vì exit trong trường hợp đó. - glenn jackman
Tôi chỉ muốn cảm ơn bất cứ ai đã cố sửa lỗi cú pháp của tôi, mặc dù chỉnh sửa của bạn đã bị từ chối. Tôi xin lỗi họ đã từ chối nó; bạn đã đúng. Cảm ơn bạn đã khắc phục. - Myrddin Emrys
FWIW, tôi đã sử dụng ví dụ này để tạo một kịch bản mà tôi dự định kích hoạt thông qua một phiên SSH từ xa. Lệnh SSH của tôi trông như thế này: ssh my-server 'path/to/myscript.sh'. Khi thực hiện theo cách này, văn bản nhắc cho read -p lệnh không hiển thị. Tuy nhiên, đầu ra từ echo lệnh. Vì vậy, đối với tôi, giải pháp tốt hơn là sử dụng echo -n "Do something? " theo dõi bởi read yn. - Travesty3


Ít nhất năm câu trả lời cho một câu hỏi chung chung.

Phụ thuộc vào

  •  tuân thủ: có thể hoạt động trên các hệ thống kém với chung  môi trường
  •  cụ thể: sử dụng cái gọi là bashisms

và nếu bạn muốn

  • câu hỏi / trả lời đơn giản `'trong dòng' '(các giải pháp chung)
  • giao diện được định dạng đẹp, như  hoặc nhiều đồ họa hơn bằng cách sử dụng libgtk hoặc libqt ...
  • sử dụng khả năng đọc lịch sử mạnh mẽ

1. Các giải pháp chung của POSIX

Bạn có thể sử dụng read lệnh, tiếp theo là if ... then ... else:

echo -n "Is this a good question (y/n)? "
read answer

# if echo "$answer" | grep -iq "^y" ;then


375
2018-01-10 10:53



Lưu ý rằng stty cung cấp -g tùy chọn để sử dụng: old_stty=$(stty -g); stty raw -echo; …; stty "$old_stty". Điều này khôi phục cài đặt chính xác như chúng đã được tìm thấy, có thể hoặc có thể không giống như stty -sane. - Jonathan Leffler
read answer sẽ giải thích các dấu gạch chéo ngược trước dấu cách và nguồn cấp dữ liệu dòng và nếu không, chúng sẽ loại bỏ chúng hiếm khi được dự định. Sử dụng read -r answer thay vào đó theo SC2162. - vlfig
@vlfig A đồng ý: mong đợi các dấu gạch chéo ngược từ đầu vào của người dùng trong Có / Không / Hủy hộp thoại là hiếm khi dự định... Tôi nghĩ đó là lý do chính bởi vì tôi đã không sử dụng -r Tùy chọn. - F. Hauri
Phương pháp "Sử dụng lịch sử của readline" quá khó hiểu cho câu hỏi của OP. Tôi rất vui vì bạn đã bao gồm nó. Tôi có hàng tá kịch bản phức tạp hơn nhiều mà tôi dự định cập nhật với mẫu đó! - Bruno Bronosky
Bạn có thể dùng case cho POSIX cũng như bash (sử dụng điều kiện ký tự đại diện thay vì một chuỗi con bash: case $answer in; [Yy]* ) echo Yes ;;), nhưng tôi thích sử dụng câu lệnh có điều kiện thay thế, ưu tiên [ "$answer" != "${answer#[Yy]}" ] trên của bạn echo "$answer" | grep -iq ^y. Nó di động hơn (một số greps không GNU không thực hiện -q chính xác) và nó không có cuộc gọi hệ thống. ${answer#[Yy]} sử dụng mở rộng tham số để xóa Y hoặc là y từ đầu $answer, gây ra sự bất bình đẳng khi có mặt. Điều này làm việc trong bất kỳ vỏ POSIX (dấu gạch ngang, ksh, bash, zsh, busybox, vv). - Adam Katz


echo "Please enter some input: "
read input_variable
echo "You entered: $input_variable"

333
2017-10-22 17:08



Tôi không đồng ý, vì nó chỉ thực hiện một phần chức năng của hộp thoại 'Có, Không, Hủy' trong DOS. Phần không thực hiện được là kiểm tra đầu vào ... lặp lại cho đến khi nhận được câu trả lời hợp lệ. - Myrddin Emrys
(Tiêu đề câu hỏi ban đầu là "Làm cách nào để nhắc nhập liệu trong tập lệnh shell Linux?") - Pistos
Nhưng mô tả câu hỏi ban đầu không thay đổi và luôn được yêu cầu trả lời lời nhắc Có / Không / Hủy. Tiêu đề đã được cập nhật để rõ ràng hơn so với bản gốc của tôi, nhưng mô tả câu hỏi luôn rõ ràng (theo ý kiến ​​của tôi). - Myrddin Emrys


Bạn có thể sử dụng tích hợp sẵn đọc chỉ huy ; Sử dụng -p tùy chọn để nhắc người dùng bằng một câu hỏi.

Kể từ BASH4, giờ đây bạn có thể sử dụng -i để đề xuất câu trả lời, vì vậy người dùng chỉ phải nhấn return để nhập nó:

read -e -p "Enter the path to the file: " -i "/usr/local/etc/" FILEPATH
echo $FILEPATH

(Nhưng hãy nhớ sử dụng tùy chọn "readline" -e để cho phép chỉnh sửa đường bằng các phím mũi tên)

Nếu bạn muốn có một "có / không" logic, bạn có thể làm một cái gì đó như thế này:

read -e -p "
List the content of your home dir ? [Y/n] " YN

[[ $YN == "y" || $YN == "Y" || $YN == "" ]] && ls -la ~/

117
2018-05-13 04:44



Cần lưu ý rằng FILEPATH là tên biến mà bạn đã chọn và được đặt với câu trả lời cho dấu nhắc lệnh. Vì vậy, nếu bạn đã chạy rồi vlc "$FILEPATH", ví dụ, vlc sẽ mở tập tin đó. - Ken Sharp


Bash có lựa chọn vì mục đích này.

select result in Yes No Cancel
do
    echo $result
done

95
2017-10-22 18:14



+1 Giải pháp đơn giản. Chỉ có điều: Điều này sẽ nhắc và promt và nhắc ... cho đến khi bạn thêm một exit phía trong :) - kaiser
(kaiser: Để thoát khỏi nó, chỉ cần nhập EOT: Ctrl-D. Nhưng tất nhiên, mã thực sự sử dụng nó sẽ cần một break hoặc một lối ra trong cơ thể.) - Zorawar
Điều này sẽ không cho phép bạn nhập y hoặc n, mặc dù.Bạn chọn bằng cách nhập 1 2 hoặc 3. - djjeck
exitsẽ thoát toàn bộ tập lệnh, break sẽ chỉ thoát khỏi vòng lặp bạn đang ở (nếu bạn đang ở trên while hoặc là case vòng lặp) - wranvaud


read -p "Are you alright? (y/n) " RESP
if [ "$RESP" = "y" ]; then
  echo "Glad to hear it"
else
  echo "You need more bash programming"
fi

51
2018-02-03 13:23





Đây là một cái gì đó tôi đặt lại với nhau:

#!/bin/sh

promptyn () {
    while true; do
        read -p "$1 " yn
        case $yn in
            [Yy]* ) return 0;;
            [Nn]* ) return 1;;
            * ) echo "Please answer yes or no.";;
        esac
    done
}

if promptyn "is the sky blue?"; then
    echo "yes"
else
    echo "no"
fi

Tôi là người mới bắt đầu, vì vậy hãy lấy cái này bằng một hạt muối, nhưng nó có vẻ hoạt động.


27
2017-08-30 17:59



Nếu bạn thay đổi case $yn in đến case ${yn:-$2} in thì bạn có thể sử dụng đối số thứ hai làm giá trị mặc định, Y hoặc N. - jchook


Bạn muốn:

  • Lệnh nội trang Bash (tức là di động)
  • Kiểm tra TTY
  • Câu trả lời mặc định
  • Hết giờ
  • Câu hỏi tô màu

Đoạn trích

do_xxxx=y                      # In batch mode => Default is Yes
[[ -t 0 ]] &&                  # If TTY => Prompt the question
read -n 1 -p $'\e[1;32m
Do xxxx? (Y/n)\e[0m ' do_xxxx  # Store the answer in $do_xxxx
if [[ $do_xxxx =~ ^(y|Y|)$ ]]  # Do if 'y' or 'Y' or empty
then
    xxxx
fi

Giải thích

  • [[ -t 0 ]] && read ... => Lệnh gọi read nếu TTY
  • read -n 1 => Đợi một ký tự
  • $'\e[1;32m ... \e[0m ' => In màu xanh lục
    (màu xanh lá cây là tốt vì có thể đọc được trên cả nền trắng / đen)
  • [[ $do_xxxx =~ ^(y|Y|)$ ]] => bash regex

Timeout => Câu trả lời mặc định là Không

do_xxxx=y
[[ -t 0 ]] && {                   # Timeout 5 seconds (read -t 5)
read -t 5 -n 1 -p $'\e[1;32m
Do xxxx? (Y/n)\e[0m ' do_xxxx ||  # read 'fails' on timeout
do_xxxx=n ; }                     # Timeout => answer No
if [[ $do_xxxx =~ ^(y|Y|)$ ]]
then
    xxxx
fi

22
2017-12-18 11:36





inquire ()  {
  echo  -n "$1 [y/n]? "
  read answer
  finish="-1"
  while [ "$finish" = '-1' ]
  do
    finish="1"
    if [ "$answer" = '' ];
    then
      answer=""
    else
      case $answer in
        y | Y | yes | YES ) answer="y";;
        n | N | no | NO ) answer="n";;
        *) finish="-1";
           echo -n 'Invalid response -- please reenter:';
           read answer;;
       esac
    fi
  done
}

... other stuff

inquire "Install now?"

...

21
2017-10-22 17:08



Đặt bốn dấu cách vào đầu mỗi dòng để giữ nguyên định dạng mã. - Jouni K. Seppänen
Tại sao chúng tôi cung cấp 'y' và 'n' làm tham số để truy vấn () nếu các chuyển mạch trường hợp được mã hóa cứng? Đó chỉ là yêu cầu lạm dụng. Chúng là các tham số cố định, không thể thay đổi được, do đó, echo trên dòng 2 nên đọc: echo -n "$ 1 [Y / N]?" Chúng không thể thay đổi được, vì vậy chúng không được cung cấp. - Myrddin Emrys
@MyrddinEmrys Bạn có thể vui lòng xây dựng nhận xét của mình không? Hoặc đăng liên kết tới một bài viết hoặc một vài từ khóa để tôi có thể tự nghiên cứu. - Mateusz Piotrowski
@MateuszPiotrowski Câu trả lời đã được chỉnh sửa và cải thiện kể từ khi tôi đưa ra nhận xét của mình. Bạn có thể nhấp vào liên kết 'Ngày 23 tháng 12' đã chỉnh sửa ở trên để xem tất cả các phiên bản trước của câu trả lời này. Trở lại năm 2008, mã này khá khác nhau. - Myrddin Emrys


Cách dễ nhất để đạt được điều này với số dòng ít nhất là như sau:

read -p "<Your Friendly Message here> : y/n/cancel" CONDITION;

if [ "$CONDITION" == "y" ]; then
   # do something here!
fi

Các if chỉ là một ví dụ: đó là vào bạn làm thế nào để xử lý biến này.


19
2018-03-03 21:22





Giải pháp này đọc một ký tự đơn và gọi hàm trên trả lời có.

read -p "Are you sure? (y/n) " -n 1
echo
if [[ $REPLY =~ ^[Yy]$ ]]; then
    do_something      
fi

15
2017-11-15 07:04



tại sao 'echo'? - Jav
@Jav echo in một dòng mới sau khi phản ứng của bạn. Nếu không có nó, điều tiếp theo sẽ được in sẽ xuất hiện ngay lập tức sau câu trả lời của bạn trên cùng một dòng. Thử xóa echo để xem cho chính mình. - Dennis