Voglio mettere in pausa l'input in uno script di shell e richiedere all'utente scelte.
La domanda standard Yes
, No
o Cancel
tipo.
Come posso farlo in un tipico prompt di bash?
read
comando per richiedere
Voglio mettere in pausa l'input in uno script di shell e richiedere all'utente scelte.
La domanda standard Yes
, No
o Cancel
tipo.
Come posso farlo in un tipico prompt di bash?
read
comando per richiedere
Risposte:
Il metodo più semplice e ampiamente disponibile per ottenere l'input dell'utente al prompt della shell è il read
comando. Il modo migliore per illustrarne l'uso è una semplice dimostrazione:
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
Un altro metodo, indicato da Steven Huwig , è il select
comando di Bash . Ecco lo stesso esempio usando 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
Con select
te non è necessario disinfettare l'input: visualizza le opzioni disponibili e si digita un numero corrispondente alla propria scelta. Inoltre, esegue un ciclo automatico, quindi non è necessario while true
riprovare un ciclo se forniscono input non validi.
Inoltre, Léa Gris ha dimostrato un modo di rendere agnostica la lingua della richiesta nella sua risposta . Adattare il mio primo esempio per servire meglio più lingue potrebbe apparire così:
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
Ovviamente qui restano non tradotte altre stringhe di comunicazione (Installa, Rispondi) che dovrebbero essere affrontate in una traduzione più completa, ma anche una traduzione parziale sarebbe utile in molti casi.
Infine, controlla l' eccellente risposta di F. Hauri .
exit
per non break
chiudere la scheda quando ho selezionato 'no'.
break
nel select
se non c'è loop?
A seconda di
e se vuoi
È possibile utilizzare il read
comando, seguito da 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
(Grazie al commento di Adam Katz : sostituito il test sopra con uno che è più portatile ed evita un fork :)
Ma se non vuoi che l'utente debba premere Return, puoi scrivere:
( Modificato: come giustamente suggerisce @JonathanLeffler, salvare la configurazione di stty potrebbe essere meglio che costringerli semplicemente a diventare sani di mente .)
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
Nota: questo è stato testato sottosh, bash, ksh, trattino e busybox!
Lo stesso, ma aspettando esplicitamente yo 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
Ci sono molti strumenti che sono stati costruiti usando libncurses
, libgtk
, libqt
o altre librerie grafiche. Ad esempio, usando whiptail
:
if whiptail --yesno "Is this a good question" 20 60 ;then
echo Yes
else
echo No
fi
A seconda del sistema in uso, potrebbe essere necessario sostituirlo whiptail
con un altro strumento simile:
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
dove 20
è l'altezza della finestra di dialogo in numero di righe ed 60
è la larghezza della finestra di dialogo. Tutti questi strumenti hanno quasi la stessa sintassi.
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
Preferisco usare in case
modo da poter anche provare yes | ja | si | oui
se necessario ...
In bash, possiamo specificare la lunghezza dell'input previsto per il read
comando:
read -n 1 -p "Is this a good question (y/n)? " answer
In bash, il read
comando accetta un parametro di timeout , che potrebbe essere utile.
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
Finestre di dialogo più sofisticate, oltre a semplici yes - no
scopi:
dialog --menu "Is this a good question" 20 60 12 y Yes n No m Maybe
Barra di avanzamento:
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
)
Piccola 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
Più campione? Dai un'occhiata all'utilizzo di whiptail per scegliere il dispositivo USB e il selettore di archiviazione rimovibile USB: USBKeyChooser
Esempio:
#!/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
Questo creerà un file .myscript.history
nella $HOME
directory, che è possibile utilizzare i comandi di storia di readline, come Up, Down, Ctrl+ re altri.
stty
prevede l' -g
opzione per l'uso: old_stty=$(stty -g); stty raw -echo; …; stty "$old_stty"
. Ciò ripristina l'impostazione esattamente come sono state trovate, che può essere o meno la stessa stty -sane
.
case
POSIX e bash (usa una condizione jolly piuttosto che una sottostringa bash:) case $answer in; [Yy]* ) echo Yes ;;
, ma preferisco invece usare un'istruzione condizionale, preferendo [ "$answer" != "${answer#[Yy]}" ]
la tua echo "$answer" | grep -iq ^y
. È più portatile (alcuni greps non GNU non implementano -q
correttamente) e non ha la chiamata di sistema. ${answer#[Yy]}
utilizza l'espansione dei parametri per rimuovere Y
o y
dall'inizio di $answer
, causando una disuguaglianza quando uno dei due è presente. Funziona con qualsiasi shell POSIX (trattino, ksh, bash, zsh, busybox, ecc.).
echo "Please enter some input: "
read input_variable
echo "You entered: $input_variable"
È possibile utilizzare il comando di lettura integrato ; Utilizzare l' -p
opzione per richiedere all'utente una domanda.
Da BASH4, ora puoi usare -i
per suggerire una risposta:
read -e -p "Enter the path to the file: " -i "/usr/local/etc/" FILEPATH
echo $FILEPATH
(Ricorda però di utilizzare l'opzione "readline" -e
per consentire la modifica delle linee con i tasti freccia)
Se vuoi una logica "sì / no", puoi fare qualcosa del genere:
read -e -p "
List the content of your home dir ? [Y/n] " YN
[[ $YN == "y" || $YN == "Y" || $YN == "" ]] && ls -la ~/
FILEPATH
è il nome della variabile che hai scelto ed è impostato con la risposta al prompt dei comandi. Quindi, se dovessi eseguire vlc "$FILEPATH"
, ad esempio, vlc
aprire quel file.
-e
secondo esempio (semplice sì / no)?
-e -p
invece di -ep
?
-e
opzione / flag, potresti (a seconda dell'implementazione) non essere in grado di digitare "y", quindi cambiare idea e sostituirlo con una "n" (o qualsiasi altra cosa); Quando si documenta un comando, elencare le opzioni separatamente è meglio per leggibilità / chiarezza, tra le altre ragioni.
Bash ha scelto per questo scopo.
select result in Yes No Cancel
do
echo $result
done
exit
interno :)
Ctrl-D
Ma ovviamente, il codice reale che lo utilizza avrà bisogno di una pausa o di un'uscita nel corpo.)
exit
uscirà dallo script tutti insieme, break
uscirà solo dal loop in cui ci si trova (se si è in un while
o case
loop)
Ecco qualcosa che ho messo insieme:
#!/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
Sono un principiante, quindi prendilo con un granello di sale, ma sembra funzionare.
case $yn in
a case ${yn:-$2} in
allora puoi usare il secondo argomento come valore predefinito, Y o N.
case $yn
per case "${yn:-Y}"
avere sì come predefinito
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 ...
=> Chiama il comando read
se TTYread -n 1
=> Attendi un carattere$'\e[1;32m ... \e[0m '
=> Stampa in verde [[ $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
Il modo più semplice per raggiungere questo obiettivo con il minor numero di righe è il seguente:
read -p "<Your Friendly Message here> : y/n/cancel" CONDITION;
if [ "$CONDITION" == "y" ]; then
# do something here!
fi
Questo if
è solo un esempio: dipende da te come gestire questa variabile.
Usa il read
comando:
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
e poi tutte le altre cose di cui hai bisogno
Questa soluzione legge un singolo carattere e chiama una funzione su una risposta sì.
read -p "Are you sure? (y/n) " -n 1
echo
if [[ $REPLY =~ ^[Yy]$ ]]; then
do_something
fi
echo
per vedere di persona.
Per ottenere una bella casella di input simile a ncurses, utilizzare la finestra di dialogo comandi in questo modo:
#!/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
Il pacchetto di dialogo è installato di default almeno con SUSE Linux. Sembra:
read -e -p "Enter your choice: " choice
L' -e
opzione consente all'utente di modificare l'input usando i tasti freccia.
Se si desidera utilizzare un suggerimento come input:
read -e -i "yes" -p "Enter your choice: " choice
-i
L'opzione stampa un input suggestivo.
-e
-i
non lavorare in sh (Bourne shell), ma la domanda è taggata bash
È possibile utilizzare il valore predefinito REPLY
su a read
, convertire in lettere minuscole e confrontarlo con un insieme di variabili con un'espressione.
Lo script supporta anche 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
È possibile gestire una scelta "Sì / No" in base alle impostazioni locali in una shell POSIX; usando le voci della LC_MESSAGES
categoria locale, witch fornisce schemi RegEx già pronti per abbinare un input e stringhe per localizzato Sì No.
#!/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: Come @Urhixidur ha menzionato nel suo commento :
Sfortunatamente, POSIX specifica solo i primi due (yesexpr e noexpr). Su Ubuntu 16, yesstr e nostr sono vuoti.
Vedi: https://www.ee.ryerson.ca/~courses/ele709/susv4/xrat/V4_xbd_chap07.html#tag_21_07_03_06
LC_MESSAGES
Le parole chiave
yesstr
enostr
locale e gli elementiYESSTR
eNOSTR
langinfo erano precedentemente utilizzati per abbinare le risposte affermative e negative dell'utente. Nel POSIX.1-2008, ilyesexpr
,noexpr
,YESEXPR
, eNOEXPR
le espressioni regolari estese hanno li ha sostituiti. Le applicazioni dovrebbero utilizzare le strutture di messaggistica generali basate su impostazioni locali per inviare messaggi di richiesta che includono risposte di esempio desiderate.
In alternativa, usando le localizzazioni nel modo 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
La risposta viene abbinata utilizzando regexps forniti dall'ambiente locale.
Per tradurre i messaggi rimanenti, utilizzare bash --dump-po-strings scriptname
per generare le stringhe di po per la localizzazione:
#: 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
e noexpr
in un ambiente shell, è usarlo nello specifico abbinamento RegEx di Bashif [[ "$yn" =~ $yesexpr ]]; then echo $"Answered yes"; else echo $"Answered no"; fi
Ecco un approccio più lungo, ma riutilizzabile e modulare:
0
= sì e 1
= nozsh
e bash
.Si noti che N
è in maiuscolo. Qui viene premuto Invio, accettando il valore predefinito:
$ confirm "Show dangerous command" && echo "rm *"
Show dangerous command [y/N]?
Si noti inoltre che è [y/N]?
stato aggiunto automaticamente. Il "no" predefinito è accettato, quindi non viene ripetuto nulla.
Richiama finché non viene fornita una risposta valida:
$ confirm "Show dangerous command" && echo "rm *"
Show dangerous command [y/N]? X
Show dangerous command [y/N]? y
rm *
Nota che Y
è in maiuscolo:
$ confirm_yes "Show dangerous command" && echo "rm *"
Show dangerous command [Y/n]?
rm *
Sopra, ho appena premuto Invio, quindi il comando è stato eseguito.
y
on
$ 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
Qui, 1
o falso è stato restituito. Tieni presente che con questa funzione di livello inferiore dovrai fornire la tua[y/n]?
prompt.
# 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]?
eShow dangerous command [Y/n]? [y/n]?
Ci scusiamo per la pubblicazione su un post così vecchio. Alcune settimane fa stavo affrontando un problema simile, nel mio caso avevo bisogno di una soluzione che funzionasse anche all'interno di uno script di installazione online, ad esempio:curl -Ss https://raw.github.com/_____/installer.sh | bash
L'utilizzo read yesno < /dev/tty
funziona bene per me:
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
Spero che questo aiuti qualcuno.
tty
input come hai fatto avrebbe fatto anche per te, e ho anche ottenuto un loop su input errato (immagina alcuni caratteri nel buffer; il tuo metodo costringerebbe l'utente a scegliere sempre no).
Ho notato che nessuno ha pubblicato una risposta che mostra il menu echo multilinea per un input utente così semplice, quindi ecco il mio passo avanti:
#!/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
Questo metodo è stato pubblicato nella speranza che qualcuno potesse trovarlo utile e risparmiare tempo.
Versione a scelta multipla:
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
}
Esempio:
$ 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
$
Verrà impostato REPLY
su y
(all'interno dello script).
Ti suggerisco di usare la finestra di dialogo ...
Apprendista Linux: migliora gli script di Bash Shell usando la finestra di dialogo
Il comando dialog abilita l'uso delle finestre negli script della shell per renderne più interattivo l'uso.
è semplice e facile da usare, c'è anche una versione di gnome chiamata gdialog che accetta esattamente gli stessi parametri, ma mostra lo stile della GUI su X.
Ispirato dalle risposte di @Mark e @Myrddin, ho creato questa funzione per un prompt universale
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
}
usalo così:
unipromtp "Select an option: (a)-Do one (x)->Do two (f)->Do three : " "a x f" selection
echo "$selection"
più generico sarebbe:
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
}
Un modo semplice per farlo è con xargs -p
o gnuparallel --interactive
.
Mi piace il comportamento di xargs un po 'meglio per questo perché esegue ogni comando immediatamente dopo il prompt come altri comandi unix interattivi, piuttosto che raccogliere gli yess da eseguire alla fine. (Puoi Ctrl-C dopo aver superato quelli che volevi.)
per esempio,
echo *.xml | xargs -p -n 1 -J {} mv {} backup/
xargs --interactive
è limitato a sì o no. Finché è tutto ciò di cui hai bisogno, può essere sufficiente, ma la mia domanda originale ha fornito un esempio con tre possibili risultati. Mi piace davvero che sia streaming; molti scenari comuni trarrebbero beneficio dalla sua capacità di essere convogliato.
Come amico di un comando a una riga ho usato quanto segue:
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=;
Scritto longform, funziona così:
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=;
Ho usato la case
frase un paio di volte in uno scenario del genere, usare la dichiarazione case è un buon modo per farlo. Un while
loop, che ecapsula il case
blocco, che utilizza una condizione booleana può essere implementato per mantenere un controllo ancora maggiore del programma e soddisfare molti altri requisiti. Dopo che tutte le condizioni sono state soddisfatte, è break
possibile utilizzare una a che riporterà il controllo alla parte principale del programma. Inoltre, per soddisfare altre condizioni, ovviamente è possibile aggiungere istruzioni condizionali per accompagnare le strutture di controllo: case
istruzione e possibilewhile
loop.
Esempio di utilizzo di una case
dichiarazione per soddisfare la tua richiesta
#! /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
In risposta ad altri:
Non è necessario specificare maiuscole / minuscole in BASH4, basta usare ',,' per rendere una var minuscola. Inoltre, non mi piace molto inserire il codice all'interno del blocco di lettura, ottenere il risultato e gestirlo al di fuori del blocco di lettura IMO. Includi anche una 'q' per uscire dall'IMO. Infine, perché digitare 'yes' basta usare -n1 e premere y.
Esempio: l'utente può premere y / n e anche q per uscire.
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
La maggior parte delle volte in tali scenari, è necessario continuare a eseguire lo script fino a quando l'utente continua a immettere "yes" e deve interrompere solo quando l'utente immette "no". Lo snippet di seguito ti aiuterà a raggiungere questo obiettivo!
#!/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]
un'opzione, quella in maiuscolo è di default, ovvero il[Yn]
valore predefinito è "sì" e il[yN]
valore predefinito è "no". Vedi ux.stackexchange.com/a/40445/43532