Bir kabuk komut dosyasında girişi duraklatmak ve seçimler için kullanıcıdan sormak istiyorum.
Standart Yes, Noya Canceltip bir soru.
Bunu tipik bir bash isteminde nasıl başarabilirim?
Bir kabuk komut dosyasında girişi duraklatmak ve seçimler için kullanıcıdan sormak istiyorum.
Standart Yes, Noya Canceltip bir soru.
Bunu tipik bir bash isteminde nasıl başarabilirim?
Yanıtlar:
Kabuk isteminde kullanıcı girişi almanın en basit ve en yaygın yöntemi readkomuttur. Kullanımını göstermenin en iyi yolu basit bir gösteri:
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
Diğer bir yöntem, işaret tarafından Steven Huwig , Bash'in olan selectkomut. İşte aynı örneği kullanarak 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
İle selectsize girdileri gerekmez - bu mevcut seçenekler görüntüler ve seçtiğiniz karşılık gelen bir sayı yazın. Ayrıca otomatik olarak döngüye girer, bu nedenle while truegeçersiz giriş verirse yeniden denemek için bir döngüye gerek yoktur .
Ayrıca Léa Gris , istek dilini yanıtında agnostik hale getirmenin bir yolunu gösterdi . İlk örneğimi birden çok dile daha iyi hizmet verecek şekilde uyarlamak şöyle görünebilir:
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
Açıkçası, diğer iletişim dizeleri burada daha tam olarak tamamlanmış bir çeviride ele alınması gereken tercüme edilmemiş halde kalır (Kur, Cevapla), ancak çoğu durumda kısmi bir çeviri bile yardımcı olacaktır.
Son olarak, kontrol edin mükemmel cevabı ile F. Hauri .
exitiçin breakben 'hayır' seçildiğinde sekme kapatmasını tutmak.
breakiçinde selecteğer hiçbir döngü var mı?
Bağlı olarak
ve eğer istersen
readKomutu ve ardından şunu kullanabilirsiniz 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
( Adam Katz'ın yorumu sayesinde : Yukarıdaki testi daha taşınabilir olan ve bir çataldan kaçınan bir testle değiştirdi :)
Ancak kullanıcının vurmasını istemiyorsanız Returnşunları yazabilirsiniz:
( Düzenlendi: @JonathanLeffler'in haklı olarak önerdiği gibi, stty'nin yapılandırmasını kaydetmek onları aklı başında tutmaya zorlamaktan daha iyi olabilir .)
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
Not: Bu,sh, darbe, ksh, tire ve busybox!
Aynı, ancak açıkça yveya 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
Kullanılarak geliştirilmiş birçok araç vardır libncurses, libgtk, libqtveya diğer grafik kütüphaneler. Örneğin, şunu kullanarak whiptail:
if whiptail --yesno "Is this a good question" 20 60 ;then
echo Yes
else
echo No
fi
Sisteminize bağlı olarak, whiptailbaşka bir benzer araçla değiştirmeniz gerekebilir :
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
Burada 20iletişim kutusunun satır sayısı cinsinden yüksekliği ve iletişim kutusunun 60genişliği. Bu araçların hepsi aynı sözdizimine sahiptir.
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
Kullanmayı tercih ederim, caseböylece yes | ja | si | ouigerekirse test edebilirim ...
Bash altında, readkomut için amaçlanan girişin uzunluğunu belirleyebiliriz :
read -n 1 -p "Is this a good question (y/n)? " answer
Bash altında, readkomut faydalı olabilecek bir zaman aşımı parametresini kabul eder .
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
Basit yes - noamaçların ötesinde daha sofistike iletişim kutuları :
dialog --menu "Is this a good question" 20 60 12 y Yes n No m Maybe
İlerleme çubuğu:
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
)
Küçük demo:
#!/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
Daha fazla örnek? Göz at USB cihazını seçmek için whiptail kullanma ve USB çıkarılabilir depolama seçici: USBKeyChooser
Misal:
#!/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
Bu bir dosya oluşturacaktır .myscript.historysizin de $HOMEsizin gibi, Readline'ın geçmişi komutlarını kullanabilirsiniz daha dizinde Up, Down, Ctrl+ rve diğerleri.
sttysağlayan -gkullanımı için seçenek: old_stty=$(stty -g); stty raw -echo; …; stty "$old_stty". Bu, ayarı tam olarak bulundukları gibi geri yükler; bu, aynı olabilir veya olmayabilir stty -sane.
case(joker koşulu yerine bash alt dize kullanın: yanı bash olarak POSIX case $answer in; [Yy]* ) echo Yes ;;), ama lehine yerine koşullu deyimi kullanmayı tercih [ "$answer" != "${answer#[Yy]}" ]üzerinde senin echo "$answer" | grep -iq ^y. Daha taşınabilir (bazı GNU harici açılımlar -qdoğru şekilde uygulanmıyor ) ve sistem çağrısı yok. ${answer#[Yy]}parametresini genişletmek için Yveya ybaşlangıcından itibaren parametre genişlemesi kullanır ve bu $answerdurum her ikisinde de eşitsizliğe neden olur. Bu, herhangi bir POSIX kabuğunda (tire, ksh, bash, zsh, busybox vb.) Çalışır.
echo "Please enter some input: "
read input_variable
echo "You entered: $input_variable"
Yerleşik okuma komutunu kullanabilirsiniz; -pKullanıcıya bir soru sormak için bu seçeneği kullanın .
BASH4'ten bu yana, şimdi -ibir cevap önermek için kullanabilirsiniz :
read -e -p "Enter the path to the file: " -i "/usr/local/etc/" FILEPATH
echo $FILEPATH
(Ancak -eok tuşlarıyla satır düzenlemeye izin vermek için "readline" seçeneğini kullanmayı unutmayın )
Bir "evet / hayır" mantığı istiyorsanız, bunun gibi bir şey yapabilirsiniz:
read -e -p "
List the content of your home dir ? [Y/n] " YN
[[ $YN == "y" || $YN == "Y" || $YN == "" ]] && ls -la ~/
FILEPATHseçtiğiniz değişken adıdır ve istemi komuta cevap ayarlanır. Böylece vlc "$FILEPATH", örneğin, eğer çalıştırırsanız , vlco dosyayı açarsınız.
-eİkinci örnekte faydası nedir (basit evet / hayır)?
-e -pBunun yerine kullanmak için herhangi bir neden var -epmı?
-eBayrak / seçenek olmadan (uygulamaya bağlı olarak) "y" yazamaz ve ardından fikrinizi değiştirip yerine "n" (veya bu konu için başka bir şey) koyamazsınız; Bir komutu belgelerken, diğer nedenlerin yanı sıra, okunabilirlik / netlik için seçenekleri ayrı olarak listelemek daha iyidir.
Bash bu amaç için seçim yaptı .
select result in Yes No Cancel
do
echo $result
done
exitiç ekleyene kadar :)
Ctrl-DAma elbette, onu kullanan gerçek kodun bir mola veya vücutta bir çıkışa ihtiyacı olacaktır.)
exitkomut dosyasından hep birlikte breakçıkacak, yalnızca bulunduğunuz döngüden çıkacak (bir whileveya casedöngüde
İşte bir araya getirdiğim bir şey:
#!/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
Ben bir acemiyim, bu yüzden bunu bir tane tuzla al, ama işe yarıyor gibi görünüyor.
case $yn iniçin case ${yn:-$2} ino zaman varsayılan değer olarak ikinci argümanı kullanabilir, Y ve N
case $yniçin case "${yn:-Y}"varsayılan olarak evet var
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 ...=> readTTY ise çağrı komuturead -n 1 => Bir karakter bekle$'\e[1;32m ... \e[0m '=> Yeşil renkte yazdır [[ $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
Bunu en az sayıda hatla elde etmenin en kolay yolu aşağıdaki gibidir:
read -p "<Your Friendly Message here> : y/n/cancel" CONDITION;
if [ "$CONDITION" == "y" ]; then
# do something here!
fi
Bu ifsadece bir örnektir: bu değişkenin nasıl işleneceği size bağlıdır.
readKomutunu kullanın :
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
ve sonra ihtiyacınız olan diğer tüm şeyler
Bu çözüm tek bir karakteri okur ve evet yanıtı için bir işlev çağırır.
read -p "Are you sure? (y/n) " -n 1
echo
if [[ $REPLY =~ ^[Yy]$ ]]; then
do_something
fi
echoKendiniz görmek için kaldırmayı deneyin .
Güzel bir ncurses benzeri giriş kutusu almak için aşağıdaki gibi komut iletişim kutusunu kullanın :
#!/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
İletişim paketi varsayılan olarak en azından SUSE Linux ile kurulur. Görünüşe göre:

read -e -p "Enter your choice: " choice
Bu -eseçenek kullanıcının ok tuşlarını kullanarak girişi düzenlemesini sağlar.
Bir öneriyi giriş olarak kullanmak istiyorsanız:
read -e -i "yes" -p "Enter your choice: " choice
-i seçeneği müstehcen bir girdi yazdırır.
-e -ish (Bourne shell) 'de çalışma, ama soru özellikle bash olarak etiketlendi ..
Varsayılanı REPLYbir a read, küçük harfe dönüştür ve ifadeli bir değişken kümesiyle karşılaştırabilirsiniz.
Betik ayrıca 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
POSIX kabuğunda yerel ayarlı bir "Evet / Hayır seçimi" işlemek mümkündür; LC_MESSAGESyerel ayar kategorisinin girişlerini kullanarak , cadı bir girdiyle eşleşmek için hazır RegEx kalıpları ve yerelleştirilmiş Evet Hayır için dizeler sağlar.
#!/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
DÜZENLEME: As @Urhixidur belirtilen onun comment :
Ne yazık ki, POSIX yalnızca ilk ikisini belirtir (yesexpr ve noexpr). Ubuntu 16'da yesstr ve nostr boştur.
Bkz. Https://www.ee.ryerson.ca/~courses/ele709/susv4/xrat/V4_xbd_chap07.html#tag_21_07_03_06
LC_MESSAGES
yesstrVenostryerel anahtar kelimeleri veYESSTRveNOSTRöğeleri langinfo eskiden maç kullanıcı olumlu ve olumsuz tepkileri için kullanıldı. POSIX.1-2008, içindeyesexpr,noexpr,YESEXPRveNOEXPRgenişletilmiş düzenli ifadeler bunların yerini almış. Uygulamalar, istenen yerel yanıt örneklerini içeren mesajlar iletmek için yerel ayar tabanlı mesajlaşma olanaklarını kullanmalıdır.
Alternatif olarak Bash yolunu yerel ayarlar kullanarak:
#!/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
Yanıt, yerel ortamın sağladığı normal ifadeler kullanılarak eşleştirilir.
Kalan iletileri çevirmek için, bash --dump-po-strings scriptnameyerelleştirmeye yönelik po dizelerini çıktılamak üzere kullanın :
#: 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 ""
yesexprve noexprbir kabuk ortamında yapılabilecek en iyi şey, Bash'in özel RegEx eşleşmesinde kullanmaktırif [[ "$yn" =~ $yesexpr ]]; then echo $"Answered yes"; else echo $"Answered no"; fi
İşte daha uzun ama yeniden kullanılabilir ve modüler bir yaklaşım:
0= Evet ve 1= hayır döndürürzshve bash.Büyük Nharfle yazıldığını unutmayın. Burada enter tuşuna basılarak varsayılan değer kabul edilir:
$ confirm "Show dangerous command" && echo "rm *"
Show dangerous command [y/N]?
Ayrıca [y/N]?, otomatik olarak eklendiğini unutmayın . Varsayılan "hayır" kabul edilir, bu nedenle hiçbir şey yankılanmaz.
Geçerli bir yanıt verilene kadar yeniden yönlendirin:
$ confirm "Show dangerous command" && echo "rm *"
Show dangerous command [y/N]? X
Show dangerous command [y/N]? y
rm *
Büyük Yharfle yazıldığını unutmayın:
$ confirm_yes "Show dangerous command" && echo "rm *"
Show dangerous command [Y/n]?
rm *
Yukarıda, enter tuşuna bastım, bu yüzden komut koştu.
yveyan$ 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
Burada 1ya da yanlış döndürüldü. Bu alt düzey işlevle kendi [y/n]?isteminizi sağlamanız gerektiğini unutmayı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
}
Show dangerous command [y/N]? [y/n]?veShow dangerous command [Y/n]? [y/n]?
Böyle eski bir gönderide yayınladığım için üzgünüm. Birkaç hafta önce benzer bir sorunla karşı karşıyaydım, benim durumumda, çevrimiçi bir yükleyici komut dosyasında da çalışan bir çözüme ihtiyacım vardı, örneğin:curl -Ss https://raw.github.com/_____/installer.sh | bash
Kullanılması read yesno < /dev/ttybenim için gayet iyi çalışıyor:
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
Umarım bu birine yardımcı olur.
ttysizin için yaptığınız gibi girişi kabul edecek şekilde uyarlamak ve aynı zamanda kötü girdide döngüye girmek (tamponda birkaç karakter hayal etmek; yönteminiz kullanıcıyı her zaman hayır seçmeye zorlar ).
Kimsenin böyle basit kullanıcı girişi için çok satırlı yankı menüsünü gösteren bir cevap yayınlamadığını fark ettim, işte burada benim gitmem:
#!/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
Bu yöntem, birinin yararlı ve zaman kazandıran bulabileceği umuduyla yayınlandı.
Çoktan seçmeli versiyon:
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
}
Misal:
$ 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
$
Bu ayarlar REPLYiçin y(komut içinde).
İletişim kutusunu kullanmanızı öneririm ...
Linux Çırağı: İletişim Kutusunu Kullanarak Bash Kabuk Komut Dosyalarını Geliştirin
Diyalog komutu, kabuk komut dosyalarında pencere kutularının kullanımını daha etkileşimli hale getirmek için kullanılmasını sağlar.
basit ve kullanımı kolaydır, aynı parametreleri alan ancak X'te GUI stilini gösteren gdialog adlı bir gnome sürümü de vardır.
@Mark ve @Myrddin'in cevaplarından esinlenerek bu işlevi evrensel bir istem için oluşturdum
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
}
şöyle kullanın:
unipromtp "Select an option: (a)-Do one (x)->Do two (f)->Do three : " "a x f" selection
echo "$selection"
daha genel:
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
}
Bunu yapmanın basit bir yolu xargs -pveya gnu'dur parallel --interactive.
Bunun için xargs'ın davranışını biraz daha beğendim çünkü her komutu komuttan sonra diğer etkileşimli unix komutları gibi hemen çalıştırıyor, sonunda çalıştırmak için yesses toplamak yerine. (İstediklerinize ulaştıktan sonra Ctrl-C tuşlarını kullanabilirsiniz.)
Örneğin,
echo *.xml | xargs -p -n 1 -J {} mv {} backup/
xargs --interactiveevet veya hayır ile sınırlıdır. İhtiyacınız olan tek şey olduğu sürece bu yeterli olabilir, ancak orijinal sorum üç olası sonuçla bir örnek verdi. Gerçi akıcı olmasını gerçekten seviyorum; birçok yaygın senaryo, pipetleme yeteneğinden yararlanır.
Bir satır komutunun arkadaşı olarak aşağıdakileri kullandım:
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=;
Yazılı uzun biçimli, şöyle çalışır:
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=;
caseBöyle bir senaryoda ifadeyi birkaç kez kullandım, durum ifadesini kullanmak bunun için iyi bir yoldur. Boole koşul uygulayan bloğu whilekapsülleyen bir döngü, caseprogramın daha fazla kontrolünü sağlamak ve diğer birçok gereksinimi yerine getirmek için uygulanabilir. Tüm koşullar yerine getirildikten sonra, breakkontrolü programın ana kısmına geri döndürecek bir a kullanılabilir. Ayrıca, diğer koşulları karşılamak için, elbette kontrol yapılarına eşlik etmek için koşullu ifadeler eklenebilir: caseifade ve olası whiledöngü.
caseİsteğinizi yerine getirmek için ifade kullanma örneği
#! /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
Başkalarına yanıt olarak:
BASH4'te büyük / küçük harf belirtmeniz gerekmez, sadece küçük harf yapmak için ',,' kullanın. Ayrıca şiddetle okuma bloğunun içine kod koyarak sevmiyorum, sonucu almak ve IMO dışında okuma bloğu ile başa çıkmak. Ayrıca, IMO'dan çıkmak için bir 'q' ekleyin. Son olarak neden 'yes' yazmanız yeterlidir -n1 kullanın ve y tuşuna basın.
Örnek: kullanıcı sadece çıkmak için y / n ve q tuşlarına basabilir.
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
Bu tür senaryolarda çoğu zaman, kullanıcı "evet" girmeye devam edene kadar komut dosyasını yürütmeye devam etmeniz gerekir ve yalnızca kullanıcı "hayır" olarak girildiğinde durması gerekir. Aşağıdaki kod parçası bunu başarmanıza yardımcı olacaktır!
#!/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]seçeneği sunarsanız, büyük harfle yazılmış olanın varsayılan olduğu, yani[Yn]varsayılan olarak "evet" ve[yN]varsayılan olarak "hayır" olacağı şekildedir . Bkz. Ux.stackexchange.com/a/40445/43532