Tôi muốn tạm dừng đầu vào trong tập lệnh shell và nhắc người dùng lựa chọn.
Các câu hỏi tiêu chuẩn Yes
, No
hoặc Cancel
loại.
Làm thế nào để tôi thực hiện điều này trong một dấu nhắc bash điển hình?
read
lệnh để nhắc
Tôi muốn tạm dừng đầu vào trong tập lệnh shell và nhắc người dùng lựa chọn.
Các câu hỏi tiêu chuẩn Yes
, No
hoặc Cancel
loại.
Làm thế nào để tôi thực hiện điều này trong một dấu nhắc bash điển hình?
read
lệnh để nhắc
Câu trả lời:
Phương pháp đơn giản và phổ biến nhất để nhận đầu vào của người dùng tại dấu nhắc shell là read
lệnh. Cách tốt nhất để minh họa 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à select
mệnh lệnh của Bash . Đâ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 vệ sinh đầ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, do đó không cần while true
vòng lặp để thử lại nếu chúng cho đầu vào không hợp lệ.
Ngoài ra, Léa Gris đã thể hiện một cách để làm cho ngôn ngữ yêu cầu trở thành bất khả tri trong câu trả lời của cô . Điều chỉnh ví dụ đầu tiên của tôi để phục vụ tốt hơn nhiều ngôn ngữ có thể giống như thế này:
set -- $(locale LC_MESSAGES)
yesptrn="$1"; noptrn="$2"; yesword="$3"; noword="$4"
while true; do
read -p "Install (${yesword} / ${noword})? " yn
case $yn in
${yesptrn##^} ) make install; break;;
${noptrn##^} ) exit;;
* ) echo "Answer ${yesword} / ${noword}.";;
esac
done
Rõ ràng các chuỗi giao tiếp khác vẫn chưa được dịch ở đây (Cài đặt, Trả lời) cần được giải quyết trong một bản dịch hoàn chỉnh hơn, nhưng ngay cả một bản dịch một phần cũng có ích trong nhiều trường hợp.
Cuối cùng, xin vui lòng kiểm tra câu trả lời tuyệt vời của F. Hauri .
exit
để break
để tránh đóng tab khi tôi chọn 'không'.
break
trong select
nếu không có vòng lặp?
Phụ thuộc vào
và nếu bạn muốn
Bạn có thể sử dụng read
lệnh, theo sau if ... then ... else
:
echo -n "Is this a good question (y/n)? "
read answer
# if echo "$answer" | grep -iq "^y" ;then
if [ "$answer" != "${answer#[Yy]}" ] ;then
echo Yes
else
echo No
fi
(Cảm ơn nhận xét của Adam Katz : Đã thay thế bài kiểm tra ở trên bằng một bài kiểm tra dễ mang theo hơn và tránh một ngã ba :)
Nhưng nếu bạn không muốn người dùng phải đánh Return, bạn có thể viết:
( Đã chỉnh sửa: Như @JonathanLeffler đã đề xuất một cách đúng đắn, việc lưu cấu hình của stty có thể tốt hơn là chỉ đơn giản là buộc họ phải tỉnh táo .)
echo -n "Is this a good question (y/n)? "
old_stty_cfg=$(stty -g)
stty raw -echo ; answer=$(head -c 1) ; stty $old_stty_cfg # Careful playing with stty
if echo "$answer" | grep -iq "^y" ;then
echo Yes
else
echo No
fi
Lưu ý: Điều này đã được thử nghiệm dướish, bash, ksh, dấu gạch ngang và bận rộn!
Tương tự, nhưng chờ đợi rõ ràng cho yhoặc n:
#/bin/sh
echo -n "Is this a good question (y/n)? "
old_stty_cfg=$(stty -g)
stty raw -echo
answer=$( while ! head -c 1 | grep -i '[ny]' ;do true ;done )
stty $old_stty_cfg
if echo "$answer" | grep -iq "^y" ;then
echo Yes
else
echo No
fi
Có nhiều công cụ đã được xây dựng sử dụng libncurses
, libgtk
, libqt
hoặc các thư viện đồ họa khác. Ví dụ whiptail
: sử dụng :
if whiptail --yesno "Is this a good question" 20 60 ;then
echo Yes
else
echo No
fi
Tùy thuộc vào hệ thống của bạn, bạn có thể cần phải thay thế whiptail
bằng một công cụ tương tự khác:
dialog --yesno "Is this a good question" 20 60 && echo Yes
gdialog --yesno "Is this a good question" 20 60 && echo Yes
kdialog --yesno "Is this a good question" 20 60 && echo Yes
trong đó 20
chiều cao của hộp thoại tính theo số dòng và 60
chiều rộng của hộp thoại. Các công cụ này đều có cú pháp gần giống nhau .
DIALOG=whiptail
if [ -x /usr/bin/gdialog ] ;then DIALOG=gdialog ; fi
if [ -x /usr/bin/xdialog ] ;then DIALOG=xdialog ; fi
...
$DIALOG --yesno ...
read -p "Is this a good question (y/n)? " answer
case ${answer:0:1} in
y|Y )
echo Yes
;;
* )
echo No
;;
esac
Tôi thích sử dụng case
hơn nên tôi thậm chí có thể kiểm tra yes | ja | si | oui
nếu cần ...
Trong bash, chúng ta có thể chỉ định độ dài của đầu vào dự định cho read
lệnh:
read -n 1 -p "Is this a good question (y/n)? " answer
Trong bash, read
lệnh chấp nhận một tham số thời gian chờ , có thể hữu ích.
read -t 3 -n 1 -p "Is this a good question (y/n)? " answer
[ -z "$answer" ] && answer="Yes" # if 'yes' have to be default choice
Hộp thoại tinh vi hơn, ngoài yes - no
mục đích đơn giản :
dialog --menu "Is this a good question" 20 60 12 y Yes n No m Maybe
Thanh tiến trình:
dialog --gauge "Filling the tank" 20 60 0 < <(
for i in {1..100};do
printf "XXX\n%d\n%(%a %b %T)T progress: %d\nXXX\n" $i -1 $i
sleep .033
done
)
Bản demo nhỏ:
#!/bin/sh
while true ;do
[ -x "$(which ${DIALOG%% *})" ] || DIALOG=dialog
DIALOG=$($DIALOG --menu "Which tool for next run?" 20 60 12 2>&1 \
whiptail "dialog boxes from shell scripts" >/dev/tty \
dialog "dialog boxes from shell with ncurses" \
gdialog "dialog boxes from shell with Gtk" \
kdialog "dialog boxes from shell with Kde" ) || exit
clear;echo "Choosed: $DIALOG."
for i in `seq 1 100`;do
date +"`printf "XXX\n%d\n%%a %%b %%T progress: %d\nXXX\n" $i $i`"
sleep .0125
done | $DIALOG --gauge "Filling the tank" 20 60 0
$DIALOG --infobox "This is a simple info box\n\nNo action required" 20 60
sleep 3
if $DIALOG --yesno "Do you like this demo?" 20 60 ;then
AnsYesNo=Yes; else AnsYesNo=No; fi
AnsInput=$($DIALOG --inputbox "A text:" 20 60 "Text here..." 2>&1 >/dev/tty)
AnsPass=$($DIALOG --passwordbox "A secret:" 20 60 "First..." 2>&1 >/dev/tty)
$DIALOG --textbox /etc/motd 20 60
AnsCkLst=$($DIALOG --checklist "Check some..." 20 60 12 \
Correct "This demo is useful" off \
Fun "This demo is nice" off \
Strong "This demo is complex" on 2>&1 >/dev/tty)
AnsRadio=$($DIALOG --radiolist "I will:" 20 60 12 \
" -1" "Downgrade this answer" off \
" 0" "Not do anything" on \
" +1" "Upgrade this anser" off 2>&1 >/dev/tty)
out="Your answers:\nLike: $AnsYesNo\nInput: $AnsInput\nSecret: $AnsPass"
$DIALOG --msgbox "$out\nAttribs: $AnsCkLst\nNote: $AnsRadio" 20 60
done
Thêm mẫu? Hãy xem Sử dụng whiptail để chọn thiết bị USB và bộ chọn lưu trữ di động USB: USBKeyChooser
Thí dụ:
#!/bin/bash
set -i
HISTFILE=~/.myscript.history
history -c
history -r
myread() {
read -e -p '> ' $1
history -s ${!1}
}
trap 'history -a;exit' 0 1 2 3 6
while myread line;do
case ${line%% *} in
exit ) break ;;
* ) echo "Doing something with '$line'" ;;
esac
done
Điều này sẽ tạo ra một tập tin .myscript.history
trong bạn $HOME
thư mục, hơn bạn có thể sử dụng lệnh lịch sử readline, như Up, Down, Ctrl+ rvà những người khác.
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ể giống hoặc không stty -sane
.
case
cho POSIX cũng như bash (sử dụng điều kiện ký tự đại diện thay vì 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 hơn, ưu tiên cho [ "$answer" != "${answer#[Yy]}" ]
bạn echo "$answer" | grep -iq ^y
. Nó dễ mang theo hơn (một số greps không phải GNU không thực hiện -q
chính xác) và nó không có lệnh gọi hệ thống. ${answer#[Yy]}
sử dụng mở rộng tham số để loại bỏ Y
hoặc y
từ đầu $answer
, gây ra sự bất bình đẳng khi có mặt. Điều này hoạt động trong bất kỳ shell POSIX (dash, ksh, bash, zsh, busybox, v.v.).
echo "Please enter some input: "
read input_variable
echo "You entered: $input_variable"
Bạn có thể sử dụng lệnh đọc tích hợp ; 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, bây giờ bạn có thể sử dụng -i
để đề xuất câu trả lời:
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 dòng bằng các phím mũi tên)
Nếu bạn muốn logic "có / không", 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 ~/
FILEPATH
là tên biến 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 vlc "$FILEPATH"
, ví dụ, vlc
sẽ mở tệp đó.
-e
ví dụ thứ hai (đơn giản có / không) là gì?
-e -p
thay vì -ep
?
-e
cờ / tùy chọn, bạn có thể (tùy thuộc vào việc triển khai) không thể nhập "y", sau đó thay đổi ý định và thay thế bằng "n" (hoặc bất cứ điều gì khác cho vấn đề đó); Khi ghi lại một lệnh, liệt kê các tùy chọn riêng biệt sẽ tốt hơn cho khả năng đọc / rõ ràng, trong số các lý do khác.
Bash đã chọn cho mục đích này.
select result in Yes No Cancel
do
echo $result
done
exit
bên trong :)
Ctrl-D
Nhưng tất nhiên, mã thực sử dụng nó sẽ cần nghỉ ngơi hay một lối ra trong cơ thể..)
exit
sẽ cùng nhau thoát khỏi tập lệnh, break
sẽ chỉ thoát khỏi vòng lặp mà bạn đang ở (nếu bạn đang ở trên một vòng lặp while
hoặc case
)
Đây là thứ tôi ghép lại:
#!/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 dùng nó với một hạt muối, nhưng nó có vẻ hiệu quả.
case $yn in
thành 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.
case $yn
để case "${yn:-Y}"
có có như mặc định
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?"
...
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
[[ -t 0 ]] && read ...
=> Gọi lệnh read
nếu TTYread -n 1
=> Đợi một ký tự$'\e[1;32m ... \e[0m '
=> In bằng màu xanh lá cây [[ $do_xxxx =~ ^(y|Y|)$ ]]
=> bash regexdo_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
Cách dễ nhất để đạt được điều này với số lượng 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
Đây if
chỉ là một ví dụ: tùy thuộc vào bạn cách xử lý biến này.
Sử dụng read
lệnh:
echo Would you like to install? "(Y or N)"
read x
# now check if $x is "y"
if [ "$x" = "y" ]; then
# do something here!
fi
và sau đó tất cả những thứ khác bạn cần
Giải pháp này đọc một ký tự đơn và gọi một hàm trên phản hồi có.
read -p "Are you sure? (y/n) " -n 1
echo
if [[ $REPLY =~ ^[Yy]$ ]]; then
do_something
fi
echo
để xem cho chính mình.
Để có được một hộp đầu vào giống như ncurses, hãy sử dụng hộp thoại lệnh như thế này:
#!/bin/bash
if (dialog --title "Message" --yesno "Want to do something risky?" 6 25)
# message box will have the size 25x6 characters
then
echo "Let's do something risky"
# do something risky
else
echo "Let's stay boring"
fi
Gói hộp thoại được cài đặt theo mặc định ít nhất là với SUSE Linux. Giống như:
read -e -p "Enter your choice: " choice
Các -e
tùy chọn cho phép người dùng chỉnh sửa các đầu vào sử dụng các phím mũi tên.
Nếu bạn muốn sử dụng một đề xuất làm đầu vào:
read -e -i "yes" -p "Enter your choice: " choice
-i
tùy chọn in một đầu vào gợi ý.
-e
-i
đừng làm việc trong sh (vỏ Bourne), nhưng câu hỏi được gắn thẻ bash cụ thể ..
Bạn có thể sử dụng mặc định REPLY
trên a read
, chuyển đổi thành chữ thường và so sánh với một tập hợp các biến có biểu thức.
Kịch bản cũng hỗ trợ ja
/ si
/oui
read -rp "Do you want a demo? [y/n/c] "
[[ ${REPLY,,} =~ ^(c|cancel)$ ]] && { echo "Selected Cancel"; exit 1; }
if [[ ${REPLY,,} =~ ^(y|yes|j|ja|s|si|o|oui)$ ]]; then
echo "Positive"
fi
Có thể xử lý "Có / Không có lựa chọn" trong miền POSIX; bằng cách sử dụng các mục của LC_MESSAGES
danh mục miền địa phương, witch cung cấp các mẫu RegEx được tạo sẵn để khớp với đầu vào và chuỗi cho địa phương Có Không.
#!/usr/bin/env sh
# Getting LC_MESSAGES values into variables
# shellcheck disable=SC2046 # Intended IFS splitting
IFS='
' set -- $(locale LC_MESSAGES)
yesexpr="$1"
noexpr="$2"
yesstr="$3"
nostr="$4"
messages_codeset="$5" # unused here, but kept as documentation
# Display Yes / No ? prompt into locale
echo "$yesstr / $nostr ?"
# Read answer
read -r yn
# Test answer
case "$yn" in
# match only work with the character class from the expression
${yesexpr##^}) echo "answer $yesstr" ;;
${noexpr##^}) echo "answer $nostr" ;;
esac
EDIT: Như @Urhixidur đã đề cập trong bình luận của mình :
Thật không may, POSIX chỉ chỉ định hai cái đầu tiên (yesexpr và noexpr). Trên Ubuntu 16, yesstr và nostr đều trống.
Xem: https://www.ee.ryerson.ca/~cifts/ele709/susv4/xrat/V4_xbd_chap07.html#tag_21_07_03_06
LC_MESSAGES
Các từ khóa
yesstr
vànostr
ngôn ngữ địa phương và các mụcYESSTR
vàNOSTR
langinfo trước đây được sử dụng để khớp với các phản hồi khẳng định và phủ định của người dùng. Trong POSIX.1-2008, cácyesexpr
,noexpr
,YESEXPR
, vàNOEXPR
biểu thức thông thường mở rộng đã thay thế chúng. Các ứng dụng nên sử dụng các phương tiện nhắn tin dựa trên miền địa phương để phát hành các tin nhắn nhắc nhở bao gồm các phản hồi mong muốn mẫu.
Hoặc sử dụng ngôn ngữ theo cách Bash:
#!/usr/bin/env bash
IFS=$'\n' read -r -d '' yesexpr noexpr _ < <(locale LC_MESSAGES)
printf -v yes_or_no_regex "(%s)|(%s)" "$yesexpr" "$noexpr"
printf -v prompt $"Please answer Yes (%s) or No (%s): " "$yesexpr" "$noexpr"
declare -- answer=;
until [[ "$answer" =~ $yes_or_no_regex ]]; do
read -rp "$prompt" answer
done
if [[ -n "${BASH_REMATCH[1]}" ]]; then
echo $"You answered: Yes"
else
echo $"No, was your answer."
fi
Câu trả lời được kết hợp bằng cách sử dụng biểu thức chính được cung cấp của môi trường miền địa phương.
Để dịch các tin nhắn còn lại, sử dụng bash --dump-po-strings scriptname
để xuất chuỗi po để bản địa hóa:
#: scriptname:8
msgid "Please answer Yes (%s) or No (%s): "
msgstr ""
#: scriptname:17
msgid "You answered: Yes"
msgstr ""
#: scriptname:19
msgid "No, was your answer."
msgstr ""
yesexpr
và noexpr
trong môi trường shell, là sử dụng nó trong kết hợp RegEx cụ thể của Bashif [[ "$yn" =~ $yesexpr ]]; then echo $"Answered yes"; else echo $"Answered no"; fi
Đâ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:
0
= có và 1
= khôngzsh
và bash
.Lưu ý rằng đó N
là 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 *
Lưu ý rằng Y
chữ 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.
y
hoặcn
$ get_yes_keypress "Here you cannot press enter. Do you like this [y/n]? "
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, 1
hoặc sai đã được trả lại. Lưu ý rằng với chức năng cấp thấp hơn này, bạn sẽ cần cung cấp [y/n]?
lời nhắc của riêng mình .
# 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
}
Show dangerous command [y/N]? [y/n]?
vàShow dangerous command [Y/n]? [y/n]?
Xin lỗi vì đã đăng trên một bài viết cũ. Vài tuần trước tôi đã phải đối mặt với một vấn đề tương tự, trong trường hợp của tôi, tôi cần một giải pháp cũng hoạt động trong tập lệnh cài đặt trực tuyến, ví dụ:curl -Ss https://raw.github.com/_____/installer.sh | bash
Sử dụng read yesno < /dev/tty
hoạt động tốt cho tôi:
echo -n "These files will be uploaded. Is this ok? (y/n) "
read yesno < /dev/tty
if [ "x$yesno" = "xy" ];then
# Yes
else
# No
fi
Hy vọng điều này sẽ giúp được ai đó.
tty
đầu vào như bạn đã làm cũng như đối với bạn và cũng bị lặp lại với đầu vào xấu (hãy tưởng tượng một vài ký tự trong bộ đệm; phương pháp của bạn sẽ buộc người dùng luôn chọn không).
Tôi nhận thấy rằng không ai đăng một câu trả lời hiển thị menu echo nhiều dòng cho đầu vào người dùng đơn giản như vậy, vì vậy đây là cách của tôi:
#!/bin/bash
function ask_user() {
echo -e "
#~~~~~~~~~~~~#
| 1.) Yes |
| 2.) No |
| 3.) Quit |
#~~~~~~~~~~~~#\n"
read -e -p "Select 1: " choice
if [ "$choice" == "1" ]; then
do_something
elif [ "$choice" == "2" ]; then
do_something_else
elif [ "$choice" == "3" ]; then
clear && exit 0
else
echo "Please select 1, 2, or 3." && sleep 3
clear && ask_user
fi
}
ask_user
Phương pháp này đã được đăng với hy vọng ai đó có thể thấy nó hữu ích và tiết kiệm thời gian.
Phiên bản nhiều lựa chọn:
ask () { # $1=question $2=options
# set REPLY
# options: x=..|y=..
while $(true); do
printf '%s [%s] ' "$1" "$2"
stty cbreak
REPLY=$(dd if=/dev/tty bs=1 count=1 2> /dev/null)
stty -cbreak
test "$REPLY" != "$(printf '\n')" && printf '\n'
(
IFS='|'
for o in $2; do
if [ "$REPLY" = "${o%%=*}" ]; then
printf '\n'
break
fi
done
) | grep ^ > /dev/null && return
done
}
Thí dụ:
$ ask 'continue?' 'y=yes|n=no|m=maybe'
continue? [y=yes|n=no|m=maybe] g
continue? [y=yes|n=no|m=maybe] k
continue? [y=yes|n=no|m=maybe] y
$
Nó sẽ được đặt REPLY
thành y
(bên trong tập lệnh).
Tôi đề nghị bạn sử dụng hộp thoại ...
Học viên Linux: Cải thiện tập lệnh Bash Shell bằng hộp thoại
Lệnh hộp thoại cho phép sử dụng các hộp cửa sổ trong các kịch bản shell để sử dụng chúng tương tác nhiều hơn.
nó đơn giản và dễ sử dụng, cũng có một phiên bản gnome gọi là gdialog có cùng tham số chính xác, nhưng hiển thị kiểu GUI trên X.
Lấy cảm hứng từ câu trả lời của @Mark và @Myrddin Tôi đã tạo chức năng này cho một dấu nhắc phổ quát
uniprompt(){
while true; do
echo -e "$1\c"
read opt
array=($2)
case "${array[@]}" in *"$opt"*) eval "$3=$opt";return 0;; esac
echo -e "$opt is not a correct value\n"
done
}
sử dụng nó như thế này:
unipromtp "Select an option: (a)-Do one (x)->Do two (f)->Do three : " "a x f" selection
echo "$selection"
chung chung hơn sẽ là:
function menu(){
title="Question time"
prompt="Select:"
options=("Yes" "No" "Maybe")
echo "$title"
PS3="$prompt"
select opt in "${options[@]}" "Quit/Cancel"; do
case "$REPLY" in
1 ) echo "You picked $opt which is option $REPLY";;
2 ) echo "You picked $opt which is option $REPLY";;
3 ) echo "You picked $opt which is option $REPLY";;
$(( ${#options[@]}+1 )) ) clear; echo "Goodbye!"; exit;;
*) echo "Invalid option. Try another one.";continue;;
esac
done
return
}
Một cách đơn giản để làm điều này là với xargs -p
hoặc gnu parallel --interactive
.
Tôi thích hành vi của xargs tốt hơn một chút vì điều này thực thi từng lệnh ngay sau dấu nhắc như các lệnh unix tương tác khác, thay vì thu thập các yess để chạy ở cuối. (Bạn có thể Ctrl-C sau khi bạn vượt qua những cái bạn muốn.)
ví dụ,
echo *.xml | xargs -p -n 1 -J {} mv {} backup/
xargs --interactive
bị giới hạn là có hoặc không. Miễn là đó là tất cả những gì bạn cần có thể là đủ, nhưng câu hỏi ban đầu của tôi đã đưa ra một ví dụ với ba kết quả có thể. Tôi thực sự thích rằng nó có thể truyền phát được; nhiều kịch bản phổ biến sẽ được hưởng lợi từ khả năng của nó được dẫn.
Là bạn của lệnh một dòng, tôi đã sử dụng như sau:
while [ -z $prompt ]; do read -p "Continue (y/n)?" choice;case "$choice" in y|Y ) prompt=true; break;; n|N ) exit 0;; esac; done; prompt=;
Viết dạng dài, nó hoạt động như thế này:
while [ -z $prompt ];
do read -p "Continue (y/n)?" choice;
case "$choice" in
y|Y ) prompt=true; break;;
n|N ) exit 0;;
esac;
done;
prompt=;
Tôi đã sử dụng case
câu lệnh một vài lần trong một kịch bản như vậy, sử dụng trường hợp thống kê là một cách tốt để thực hiện nó. Một while
vòng lặp, bao trùm case
khối, sử dụng điều kiện boolean có thể được thực hiện để giữ quyền kiểm soát chương trình nhiều hơn và đáp ứng nhiều yêu cầu khác. Sau khi tất cả các điều kiện đã được đáp ứng, một break
có thể được sử dụng sẽ chuyển điều khiển trở lại phần chính của chương trình. Ngoài ra, để đáp ứng các điều kiện khác, tất nhiên các câu lệnh có điều kiện có thể được thêm vào để đi kèm với các cấu trúc điều khiển: case
câu lệnh và while
vòng lặp có thể .
Ví dụ về việc sử dụng một case
tuyên bố để thực hiện yêu cầu của bạn
#! /bin/sh
# For potential users of BSD, or other systems who do not
# have a bash binary located in /bin the script will be directed to
# a bourne-shell, e.g. /bin/sh
# NOTE: It would seem best for handling user entry errors or
# exceptions, to put the decision required by the input
# of the prompt in a case statement (case control structure),
echo Would you like us to perform the option: "(Y|N)"
read inPut
case $inPut in
# echoing a command encapsulated by
# backticks (``) executes the command
"Y") echo `Do something crazy`
;;
# depending on the scenario, execute the other option
# or leave as default
"N") echo `execute another option`
;;
esac
exit
#!/usr/bin/env bash
@confirm() {
local message="$*"
local result=''
echo -n "> $message (Yes/No/Cancel) " >&2
while [ -z "$result" ] ; do
read -s -n 1 choice
case "$choice" in
y|Y ) result='Y' ;;
n|N ) result='N' ;;
c|C ) result='C' ;;
esac
done
echo $result
}
case $(@confirm 'Confirm?') in
Y ) echo "Yes" ;;
N ) echo "No" ;;
C ) echo "Cancel" ;;
esac
#!/usr/bin/env bash
@confirm() {
local message="$*"
local result=3
echo -n "> $message (y/n) " >&2
while [[ $result -gt 1 ]] ; do
read -s -n 1 choice
case "$choice" in
y|Y ) result=0 ;;
n|N ) result=1 ;;
esac
done
return $result
}
if @confirm 'Confirm?' ; then
echo "Yes"
else
echo "No"
fi
yn() {
if [[ 'y' == `read -s -n 1 -p "[y/n]: " Y; echo $Y` ]];
then eval $1;
else eval $2;
fi }
yn 'echo yes' 'echo no'
yn 'echo absent no function works too!'
yn(){ read -s -n 1 -p '[y/n]'; test "$REPLY" = "y" ; } yn && echo success || echo failure
Đáp lại những người khác:
Bạn không cần chỉ định trường hợp trong BASH4, chỉ cần sử dụng ',,' để tạo chữ thường var. Ngoài ra, tôi không thích đặt mã bên trong khối đọc, nhận kết quả và xử lý nó bên ngoài khối đọc IMO. Đồng thời bao gồm 'q' để thoát IMO. Cuối cùng, tại sao gõ 'có' chỉ cần sử dụng -n1 và nhấn y.
Ví dụ: người dùng có thể nhấn y / n và cả q để thoát.
ans=''
while true; do
read -p "So is MikeQ the greatest or what (y/n/q) ?" -n1 ans
case ${ans,,} in
y|n|q) break;;
*) echo "Answer y for yes / n for no or q for quit.";;
esac
done
echo -e "\nAnswer = $ans"
if [[ "${ans,,}" == "q" ]] ; then
echo "OK Quitting, we will assume that he is"
exit 0
fi
if [[ "${ans,,}" == "y" ]] ; then
echo "MikeQ is the greatest!!"
else
echo "No? MikeQ is not the greatest?"
fi
Hầu hết các trường hợp trong các tình huống như vậy, bạn cần tiếp tục thực thi tập lệnh cho đến khi người dùng tiếp tục nhập "có" và chỉ cần dừng khi người dùng nhập "không". Đoạn trích dưới đây sẽ giúp bạn đạt được điều này!
#!/bin/bash
input="yes"
while [ "$input" == "yes" ]
do
echo "execute script functionality here..!!"
echo "Do you want to continue (yes/no)?"
read input
done
[yn]
tùy chọn, tùy chọn được viết hoa là mặc định, nghĩa là[Yn]
mặc định là "có" và[yN]
mặc định là "không". Xem ux.stackexchange.com/a/40445/43532