Je souhaite suspendre la saisie dans un script shell et inviter l'utilisateur à faire des choix.
La question standard Yes
, No
ou de Cancel
type.
Comment puis-je accomplir cela dans une invite bash typique?
read
commande pour demander
Je souhaite suspendre la saisie dans un script shell et inviter l'utilisateur à faire des choix.
La question standard Yes
, No
ou de Cancel
type.
Comment puis-je accomplir cela dans une invite bash typique?
read
commande pour demander
Réponses:
La méthode la plus simple et la plus largement disponible pour obtenir une entrée utilisateur à l'invite du shell est la read
commande. La meilleure façon d'illustrer son utilisation est une démonstration simple:
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
Une autre méthode, soulignée par Steven Huwig , est le select
commandement de Bash . Voici le même exemple d'utilisation 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
Avec select
vous n'avez pas besoin de nettoyer l'entrée - elle affiche les choix disponibles et vous tapez un nombre correspondant à votre choix. Il boucle également automatiquement, il n'est donc pas nécessaire while true
de réessayer une boucle si elles donnent une entrée non valide.
Aussi, Léa Gris a démontré un moyen de rendre la langue de la demande agnostique dans sa réponse . L'adaptation de mon premier exemple pour mieux servir plusieurs langues pourrait ressembler à ceci:
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
Il est évident que d'autres chaînes de communication restent non traduites ici (Installer, Répondre) qui devraient être traitées dans une traduction plus complète, mais même une traduction partielle serait utile dans de nombreux cas.
Enfin, veuillez consulter l' excellente réponse de F. Hauri .
exit
pour ne break
pas fermer l'onglet lorsque j'ai sélectionné «non».
break
dans select
s'il n'y a pas de boucle?
Cela dépend de
et si tu veux
Vous pouvez utiliser la read
commande, suivie de 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
(Merci au commentaire d'Adam Katz : remplacement du test ci-dessus par un test plus portable et évitant une fourche :)
Mais si vous ne voulez pas que l'utilisateur frappe Return, vous pouvez écrire:
( Modifié: comme @JonathanLeffler le suggère à juste titre, enregistrer la configuration de stty pourrait être mieux que simplement les forcer à rester saines .)
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
Remarque: cela a été testé soussh, frapper, ksh, tiret et occupé!
Idem, mais en attendant explicitement you 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
Il existe de nombreux outils qui ont été construits en utilisant libncurses
, libgtk
, libqt
ou d' autres bibliothèques graphiques. Par exemple, en utilisant whiptail
:
if whiptail --yesno "Is this a good question" 20 60 ;then
echo Yes
else
echo No
fi
Selon votre système, vous devrez peut-être le remplacer whiptail
par un autre outil similaire:
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
où 20
est la hauteur de la boîte de dialogue en nombre de lignes et la 60
largeur de la boîte de dialogue. Ces outils ont tous presque la même syntaxe.
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
Je préfère utiliser case
pour pouvoir même tester yes | ja | si | oui
si besoin ...
Sous bash, nous pouvons spécifier la longueur de l'entrée prévue pour la read
commande:
read -n 1 -p "Is this a good question (y/n)? " answer
Sous bash, la read
commande accepte un paramètre de délai d'attente , ce qui pourrait être 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
Des boîtes de dialogue plus sophistiquées, au-delà de simples yes - no
objectifs:
dialog --menu "Is this a good question" 20 60 12 y Yes n No m Maybe
Barre de progression:
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
)
Petite démo:
#!/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
Plus d'échantillon? Jetez un œil à Utilisation de whiptail pour choisir un périphérique USB et un sélecteur de stockage amovible USB: USBKeyChooser
Exemple:
#!/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
Cela va créer un fichier .myscript.history
dans votre $HOME
répertoire, que vous pouvez utiliser les commandes d'histoire de readline, comme Up, Down, Ctrl+ ret d' autres.
stty
fournit l' -g
option d'utilisation: old_stty=$(stty -g); stty raw -echo; …; stty "$old_stty"
. Cela restaure le paramètre exactement tel qu'il a été trouvé, qui peut être identique ou non stty -sane
.
case
pour POSIX ainsi que bash (utilisez une condition générique plutôt qu'une sous-chaîne bash:) case $answer in; [Yy]* ) echo Yes ;;
, mais je préfère utiliser une instruction conditionnelle à la place, favorisant [ "$answer" != "${answer#[Yy]}" ]
la vôtre echo "$answer" | grep -iq ^y
. C'est plus portable (certains greps non GNU ne sont pas implémentés -q
correctement) et il n'a pas l'appel système. ${answer#[Yy]}
utilise l'expansion des paramètres pour supprimer Y
ou y
depuis le début de $answer
, provoquant une inégalité lorsque l'un ou l'autre est présent. Cela fonctionne dans n'importe quel shell POSIX (dash, ksh, bash, zsh, busybox, etc.).
echo "Please enter some input: "
read input_variable
echo "You entered: $input_variable"
Vous pouvez utiliser la commande de lecture intégrée ; Utilisez l' -p
option pour inviter l'utilisateur à poser une question.
Depuis BASH4, vous pouvez maintenant utiliser -i
pour suggérer une réponse:
read -e -p "Enter the path to the file: " -i "/usr/local/etc/" FILEPATH
echo $FILEPATH
(Mais n'oubliez pas d'utiliser l'option "readline" -e
pour autoriser l'édition de ligne avec les touches fléchées)
Si vous voulez une logique "oui / non", vous pouvez faire quelque chose comme ceci:
read -e -p "
List the content of your home dir ? [Y/n] " YN
[[ $YN == "y" || $YN == "Y" || $YN == "" ]] && ls -la ~/
FILEPATH
c'est le nom de variable que vous avez choisi et qu'il est défini avec la réponse à l'invite de commande. Donc, si vous deviez ensuite exécuter vlc "$FILEPATH"
, par exemple, vlc
ouvrirait ce fichier.
-e
deuxième exemple (simple oui / non)?
-e -p
au lieu de -ep
?
-e
indicateur / l'option, vous pourriez (selon l'implémentation) ne pas être en mesure de taper "y", puis de changer d'avis et de le remplacer par un "n" (ou toute autre chose d'ailleurs); Lors de la documentation d'une commande, répertorier les options séparément est préférable pour la lisibilité / clarté, entre autres raisons.
Bash a sélectionné à cet effet.
select result in Yes No Cancel
do
echo $result
done
exit
intérieur :)
Ctrl-D
Mais bien sûr, le vrai code qui l'utilise aura besoin d'une pause ou d'une sortie dans le corps.)
exit
quittera le script tous ensemble, break
ne quittera que la boucle dans laquelle vous vous trouvez (si vous êtes sur une boucle while
ou case
)
Voici quelque chose que j'ai mis en place:
#!/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
Je suis un débutant, alors prenez ceci avec un grain de sel, mais cela semble fonctionner.
case $yn in
en, case ${yn:-$2} in
vous pouvez utiliser le deuxième argument comme valeur par défaut, Y ou N.
case $yn
pour case "${yn:-Y}"
avoir oui par défaut
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 ...
=> Appeler la commande read
si TTYread -n 1
=> Attendez un caractère$'\e[1;32m ... \e[0m '
=> Imprimer en vert [[ $do_xxxx =~ ^(y|Y|)$ ]]
=> expression bashdo_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
La façon la plus simple d'y parvenir avec le moins de lignes est la suivante:
read -p "<Your Friendly Message here> : y/n/cancel" CONDITION;
if [ "$CONDITION" == "y" ]; then
# do something here!
fi
Le if
est juste un exemple: il est à vous comment gérer cette variable.
Utilisez la read
commande:
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
puis toutes les autres choses dont vous avez besoin
Cette solution lit un seul caractère et appelle une fonction sur une réponse oui.
read -p "Are you sure? (y/n) " -n 1
echo
if [[ $REPLY =~ ^[Yy]$ ]]; then
do_something
fi
echo
pour voir par vous-même.
Pour obtenir une jolie boîte de saisie de type ncurses, utilisez la boîte de dialogue de commande comme ceci:
#!/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
Le package de dialogue est installé par défaut au moins avec SUSE Linux. Ressemble à:
read -e -p "Enter your choice: " choice
le -e
option permet à l'utilisateur de modifier l'entrée à l'aide des touches fléchées.
Si vous souhaitez utiliser une suggestion en entrée:
read -e -i "yes" -p "Enter your choice: " choice
-i
option imprime une entrée suggestive.
-e
-i
ne fonctionne pas dans sh (Bourne shell), mais la question est taguée bash spécifiquement ..
Vous pouvez utiliser la valeur par défaut REPLY
sur a read
, convertir en minuscules et comparer à un ensemble de variables avec une expression.
Le script prend également en charge 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
Il est possible de gérer un «choix Oui / Non» sensible aux paramètres régionaux dans un shell POSIX; en utilisant les entrées duLC_MESSAGES
catégorie locale, witch fournit des modèles RegEx prêts à l'emploi pour correspondre à une entrée et des chaînes pour les localisés Oui Non.
#!/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: Comme @Urhixidur mentionné dans son commentaire :
Malheureusement, POSIX ne spécifie que les deux premiers (yesexpr et noexpr). Sur Ubuntu 16, yesstr et nostr sont vides.
Voir: https://www.ee.ryerson.ca/~courses/ele709/susv4/xrat/V4_xbd_chap07.html#tag_21_07_03_06
LC_MESSAGES
Les mots clés
yesstr
etnostr
locale et les élémentsYESSTR
etNOSTR
langinfo étaient auparavant utilisés pour faire correspondre les réponses affirmatives et négatives des utilisateurs. En POSIX.1-2008, leyesexpr
,noexpr
,YESEXPR
, et lesNOEXPR
expressions régulières les ont remplacés. Les applications doivent utiliser les fonctionnalités générales de messagerie basées sur les paramètres régionaux pour émettre des messages d'invite qui incluent des exemples de réponses souhaitées.
Vous pouvez également utiliser les paramètres régionaux de la manière 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 réponse est mise en correspondance à l'aide des expressions régulières fournies par l'environnement local.
Pour traduire les messages restants, utilisez bash --dump-po-strings scriptname
pour sortir les chaînes po pour la localisation:
#: 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
et noexpr
dans un environnement shell, est de l'utiliser dans la correspondance RegEx spécifique de Bashif [[ "$yn" =~ $yesexpr ]]; then echo $"Answered yes"; else echo $"Answered no"; fi
Voici une approche plus longue, mais réutilisable et modulaire:
0
= oui et 1
= nonzsh
et bash
.Notez que le N
est en majuscule. Ici, appuyez sur Entrée, en acceptant la valeur par défaut:
$ confirm "Show dangerous command" && echo "rm *"
Show dangerous command [y/N]?
Notez également que cela a [y/N]?
été automatiquement ajouté. Le "non" par défaut est accepté, donc rien n'est répété.
Invitez à nouveau jusqu'à ce qu'une réponse valide soit donnée:
$ confirm "Show dangerous command" && echo "rm *"
Show dangerous command [y/N]? X
Show dangerous command [y/N]? y
rm *
Notez que le Y
est en majuscule:
$ confirm_yes "Show dangerous command" && echo "rm *"
Show dangerous command [Y/n]?
rm *
Ci-dessus, je viens d'appuyer sur Entrée, donc la commande s'est exécutée.
y
oun
$ 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
Ici, 1
ou faux a été retourné. Notez qu'avec cette fonction de niveau inférieur, vous devrez fournir la vôtre[y/n]?
invite.
# 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]?
etShow dangerous command [Y/n]? [y/n]?
Désolé d'avoir posté sur un si vieux post. Il y a quelques semaines, je faisais face à un problème similaire, dans mon cas, j'avais besoin d'une solution qui fonctionnait également dans un script d'installation en ligne, par exemple:curl -Ss https://raw.github.com/_____/installer.sh | bash
L'utilisation read yesno < /dev/tty
fonctionne bien pour moi:
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
J'espère que cela aide quelqu'un.
tty
entrée comme vous l'auriez fait aurait également fait pour vous, et aussi obtenu une boucle sur une mauvaise entrée (imaginez quelques caractères dans le tampon; votre méthode obligerait l'utilisateur à toujours choisir non).
J'ai remarqué que personne n'a posté de réponse montrant un menu d'écho multi-lignes pour une entrée utilisateur aussi simple, alors voici mon coup:
#!/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
Cette méthode a été publiée dans l'espoir que quelqu'un puisse la trouver utile et gagner du temps.
Version à choix multiples:
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
}
Exemple:
$ 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
$
Il sera défini REPLY
sur y
(à l'intérieur du script).
Je vous suggère d' utiliser la boîte de dialogue ...
Apprenti Linux: Améliorez les scripts du shell Bash à l'aide de la boîte de dialogue
La commande de dialogue permet d'utiliser des fenêtres dans des scripts shell pour rendre leur utilisation plus interactive.
c'est simple et facile à utiliser, il y a aussi une version gnome appelée gdialog qui prend exactement les mêmes paramètres, mais montre le style GUI sur X.
Inspiré par les réponses de @Mark et @Myrddin, j'ai créé cette fonction pour une invite universelle
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
}
utilisez-le comme ceci:
unipromtp "Select an option: (a)-Do one (x)->Do two (f)->Do three : " "a x f" selection
echo "$selection"
plus générique serait:
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
}
Une façon simple de le faire est avec xargs -p
ou gnu parallel --interactive
.
J'aime le comportement de xargs un peu mieux pour cela car il exécute chaque commande immédiatement après l'invite comme les autres commandes unix interactives, plutôt que de collecter les oui à exécuter à la fin. (Vous pouvez Ctrl-C après avoir terminé celles que vous vouliez.)
par exemple,
echo *.xml | xargs -p -n 1 -J {} mv {} backup/
xargs --interactive
se limite à oui ou non. Tant que c'est tout ce dont vous avez besoin, cela peut être suffisant, mais ma question initiale a donné un exemple avec trois résultats possibles. J'aime vraiment que ce soit streamable cependant; de nombreux scénarios courants bénéficieraient de sa capacité à être canalisés.
En tant qu'ami d'une commande d'une ligne, j'ai utilisé ce qui suit:
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=;
Forme longue écrite, cela fonctionne comme ceci:
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=;
J'ai utilisé la case
déclaration plusieurs fois dans un tel scénario, en utilisant la déclaration de cas est une bonne façon de procéder. Une while
boucle, qui résume le case
bloc, qui utilise une condition booléenne peut être implémentée afin de garder encore plus de contrôle sur le programme et de remplir de nombreuses autres exigences. Une fois que toutes les conditions ont été remplies, un break
peut être utilisé qui passera le contrôle à la partie principale du programme. De plus, pour répondre à d'autres conditions, des instructions conditionnelles peuvent bien sûr être ajoutées pour accompagner les structures de contrôle: case
instruction et while
boucle possible .
Exemple d'utilisation d'une case
déclaration pour répondre à votre demande
#! /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
En réponse aux autres:
Vous n'avez pas besoin de spécifier la casse dans BASH4, utilisez simplement le ",," pour faire une var minuscule. Je n'aime pas non plus mettre du code à l'intérieur du bloc de lecture, obtenir le résultat et le traiter en dehors du bloc de lecture IMO. Incluez également un «q» pour quitter l'OMI. Enfin, tapez «oui», utilisez simplement -n1 et appuyez sur y.
Exemple: l'utilisateur peut appuyer sur y / n et sur q pour simplement quitter.
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 plupart du temps dans de tels scénarios, vous devez continuer à exécuter le script jusqu'à ce que l'utilisateur continue de saisir "oui" et ne doit s'arrêter que lorsque l'utilisateur entre "non". L'extrait ci-dessous vous aiderait à atteindre cet objectif!
#!/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]
option, celle qui est mise en majuscule est par défaut, c'est-[Yn]
à- dire par défaut à "oui" et par[yN]
défaut à "non". Voir ux.stackexchange.com/a/40445/43532