Bir kabuk komut dosyasında girişi duraklatmak ve seçimler için kullanıcıdan sormak istiyorum.
Standart Yes
, No
ya Cancel
tip 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
, No
ya Cancel
tip 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 read
komuttur. 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 select
komut. İş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 select
size 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 true
geç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 .
exit
için break
ben 'hayır' seçildiğinde sekme kapatmasını tutmak.
break
içinde select
eğer hiçbir döngü var mı?
Bağlı olarak
ve eğer istersen
read
Komutu 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
, libqt
veya 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, whiptail
baş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 20
iletişim kutusunun satır sayısı cinsinden yüksekliği ve iletişim kutusunun 60
geniş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, case
böylece yes | ja | si | oui
gerekirse test edebilirim ...
Bash altında, read
komut için amaçlanan girişin uzunluğunu belirleyebiliriz :
read -n 1 -p "Is this a good question (y/n)? " answer
Bash altında, read
komut 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 - no
amaç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.history
sizin de $HOME
sizin gibi, Readline'ın geçmişi komutlarını kullanabilirsiniz daha dizinde Up, Down, Ctrl+ rve diğerleri.
stty
sağlayan -g
kullanı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 -q
doğru şekilde uygulanmıyor ) ve sistem çağrısı yok. ${answer#[Yy]}
parametresini genişletmek için Y
veya y
başlangıcından itibaren parametre genişlemesi kullanır ve bu $answer
durum 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; -p
Kullanıcıya bir soru sormak için bu seçeneği kullanın .
BASH4'ten bu yana, şimdi -i
bir cevap önermek için kullanabilirsiniz :
read -e -p "Enter the path to the file: " -i "/usr/local/etc/" FILEPATH
echo $FILEPATH
(Ancak -e
ok 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 ~/
FILEPATH
seç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 , vlc
o dosyayı açarsınız.
-e
İkinci örnekte faydası nedir (basit evet / hayır)?
-e -p
Bunun yerine kullanmak için herhangi bir neden var -ep
mı?
-e
Bayrak / 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
exit
iç ekleyene kadar :)
Ctrl-D
Ama elbette, onu kullanan gerçek kodun bir mola veya vücutta bir çıkışa ihtiyacı olacaktır.)
exit
komut dosyasından hep birlikte break
çıkacak, yalnızca bulunduğunuz döngüden çıkacak (bir while
veya case
dö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 in
için case ${yn:-$2} in
o zaman varsayılan değer olarak ikinci argümanı kullanabilir, Y ve N
case $yn
iç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 ...
=> read
TTY 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 if
sadece bir örnektir: bu değişkenin nasıl işleneceği size bağlıdır.
read
Komutunu 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
echo
Kendiniz 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 -e
seç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
-i
sh (Bourne shell) 'de çalışma, ama soru özellikle bash olarak etiketlendi ..
Varsayılanı REPLY
bir 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_MESSAGES
yerel 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
yesstr
Venostr
yerel anahtar kelimeleri veYESSTR
veNOSTR
öğeleri langinfo eskiden maç kullanıcı olumlu ve olumsuz tepkileri için kullanıldı. POSIX.1-2008, içindeyesexpr
,noexpr
,YESEXPR
veNOEXPR
geniş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 scriptname
yerelleş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 ""
yesexpr
ve noexpr
bir 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ürzsh
ve bash
.Büyük N
harfle 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 Y
harfle 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.
y
veyan
$ 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 1
ya 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/tty
benim 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.
tty
sizin 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 REPLY
iç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 -p
veya 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 --interactive
evet 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=;
case
Böyle bir senaryoda ifadeyi birkaç kez kullandım, durum ifadesini kullanmak bunun için iyi bir yoldur. Boole koşul uygulayan bloğu while
kapsülleyen bir döngü, case
programı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, break
kontrolü 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: case
ifade ve olası while
dö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