Comment demander une entrée Oui / Non / Annuler dans un script shell Linux?
1445
Je souhaite suspendre la saisie dans un script shell et inviter l'utilisateur à faire des choix.
La question standard Yes, Noou de Canceltype.
Comment puis-je accomplir cela dans une invite bash typique?
Tout comme une note: la convention pour les invites est telle que si vous présentez une [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
Tyzoid
Toute personne venant ici de ZSH, voir cette réponse pour savoir comment utiliser la readcommande pour demander
smac89
Réponses:
1620
La méthode la plus simple et la plus largement disponible pour obtenir une entrée utilisateur à l'invite du shell est la readcommande. 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.";;esacdone
Une autre méthode, soulignée par Steven Huwig , est le selectcommandement de Bash . Voici le même exemple d'utilisation select:
echo "Do you wish to install this program?"
select yn in"Yes""No";docase $yn inYes) make install;break;;No) exit;;esacdone
Avec selectvous 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 truede 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}.";;esacdone
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.
En utilisant Bash dans OS X Leopard, j'ai changé exitpour ne breakpas fermer l'onglet lorsque j'ai sélectionné «non».
Trey Piepmeier
1
Comment cela fonctionne-t-il avec des options plus longues que Oui ou Non? Dans la clause case, écrivez-vous quelque chose comme: Installer le programme et ne rien faire ensuite) make install; Pause;
Shawn
1
@Shawn En utilisant la lecture, vous pouvez bien sûr utiliser n'importe quel modèle glob ou regex pris en charge par l'instruction switch du shell bash. Il fait simplement correspondre le texte tapé à vos modèles jusqu'à ce qu'il trouve une correspondance. En utilisant select , la liste des choix est donnée à la commande et elle les affiche à l'utilisateur. Vous pouvez avoir les éléments de la liste aussi longs ou aussi courts que vous le souhaitez. Je recommande de consulter leurs pages de manuel pour des informations d'utilisation complètes.
Myrddin Emrys
3
pourquoi y a-t-il breakdans selects'il n'y a pas de boucle?
Jayen
1
@akostadinov Je devrais vraiment lire davantage mon historique des modifications. Vous avez raison, je me trompe, et j'ai introduit un bug suite aux conseils de Jayan, hah. Le bug a été corrigé plus tard, mais les modifications étaient si éloignées que je ne me souvenais même pas de l'avoir changé.
Myrddin Emrys
527
Au moins cinq réponses pour une question générique.
Cela dépend de
posix conforme: pourrait fonctionner sur des systèmes pauvres avec générique coquille environnements
frapperspécifique: utilisation de soi-disant bashismes
et si tu veux
question / réponse simple `` en ligne '' (solutions génériques)
interfaces assez formatées, comme ncurses ou plus graphique en utilisant libgtk ou libqt ...
utiliser une puissante capacité d'historique de lecture
1. Solutions génériques POSIX
Vous pouvez utiliser la readcommande, suivie de if ... then ... else:
echo -n "Is this a good question (y/n)? "
read answer
(Merci au commentaire d'Adam Katz : remplacement du test ci-dessus par un test plus portable et évitant une fourche :)
POSIX, mais fonctionnalité clé unique
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 sttyif echo "$answer"| grep -iq "^y";then
echo Yeselse
echo Nofi
#/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 Yeselse
echo Nofi
Utiliser des outils dédiés
Il existe de nombreux outils qui ont été construits en utilisant libncurses, libgtk, libqtou d' autres bibliothèques graphiques. Par exemple, en utilisant whiptail:
if whiptail --yesno "Is this a good question"2060;then
echo Yeselse
echo Nofi
Selon votre système, vous devrez peut-être le remplacer whiptailpar un autre outil similaire:
dialog --yesno "Is this a good question"2060&& echo Yes
gdialog --yesno "Is this a good question"2060&& echo Yes
kdialog --yesno "Is this a good question"2060&& echo Yes
où 20est la hauteur de la boîte de dialogue en nombre de lignes et la 60largeur de la boîte de dialogue. Ces outils ont tous presque la même syntaxe.
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 casepour pouvoir même tester yes | ja | si | ouisi besoin ...
en ligne avec une caractéristique clé unique
Sous bash, nous pouvons spécifier la longueur de l'entrée prévue pour la readcommande:
read -n 1-p "Is this a good question (y/n)? " answer
Sous bash, la readcommande 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
3. Quelques astuces pour des outils dédiés
Des boîtes de dialogue plus sophistiquées, au-delà de simples yes - noobjectifs:
dialog --menu "Is this a good question"206012 y Yes n No m Maybe
Barre de progression:
dialog --gauge "Filling the tank"20600<<(for i in{1..100};do
printf "XXX\n%d\n%(%a %b %T)T progress: %d\nXXX\n" $i -1 $i
sleep .033done)
Petite démo:
#!/bin/shwhile true ;do[-x "$(which ${DIALOG%% *})"]|| DIALOG=dialog
DIALOG=$($DIALOG --menu "Which tool for next run?"2060122>&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 .0125done| $DIALOG --gauge "Filling the tank"20600
$DIALOG --infobox "This is a simple info box\n\nNo action required"2060
sleep 3if $DIALOG --yesno "Do you like this demo?"2060;thenAnsYesNo=Yes;elseAnsYesNo=No;fiAnsInput=$($DIALOG --inputbox "A text:"2060"Text here..."2>&1>/dev/tty)AnsPass=$($DIALOG --passwordbox "A secret:"2060"First..."2>&1>/dev/tty)
$DIALOG --textbox /etc/motd 2060AnsCkLst=$($DIALOG --checklist "Check some..."206012 \
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:"206012 \
" -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"2060done
#!/bin/bashset-i
HISTFILE=~/.myscript.history
history -c
history -r
myread(){
read -e -p '> ' $1
history -s ${!1}}
trap 'history -a;exit'01236while myread line;docase ${line%%*}in
exit )break;;*) echo "Doing something with '$line'";;esacdone
Cela va créer un fichier .myscript.historydans votre $HOMErépertoire, que vous pouvez utiliser les commandes d'histoire de readline, comme Up, Down, Ctrl+ ret d' autres.
Notez que sttyfournit l' -goption 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.
Jonathan Leffler
3
read answerinterprétera les barres obliques inverses avant les espaces et les sauts de ligne, et les supprimera autrement, ce qui est rarement prévu. Utilisez à la read -r answerplace selon SC2162 .
vlfig
1
La méthode "Utilisation de l'historique de readline" est terriblement inappropriée pour la question du PO. Je suis content que vous l'ayez inclus de toute façon. J'ai des dizaines de scripts beaucoup plus compliqués que j'ai l'intention de mettre à jour avec ce modèle!
Bruno Bronosky
5
Vous pouvez utiliser casepour 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 -qcorrectement) et il n'a pas l'appel système. ${answer#[Yy]}utilise l'expansion des paramètres pour supprimer You ydepuis 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.).
Adam Katz
1
@CarterPape Oui, c'était une blague! Mais dans cette réponse détallée, vous pouvez trouver beaucoup de conseils (le deuxième point présente au moins 3 méthodes différentes)! Et ... à partir d'environ 5 ans maintenant, vous êtes le premier à parler de ma méthode de comptage! ;-))
F. Hauri
349
echo "Please enter some input: "
read input_variable
echo "You entered: $input_variable"
Je ne suis pas d'accord, car il n'implémente qu'une partie des fonctionnalités de la boîte de dialogue "Oui, Non, Annuler" dans DOS. La partie qu'il ne parvient pas à mettre en œuvre est la vérification des entrées ... en boucle jusqu'à ce qu'une réponse valide soit reçue.
Myrddin Emrys
1
(Le titre de la question d'origine était "Comment puis-je demander une entrée dans un script shell Linux?")
Pistos
8
Mais la description de la question d'origine est inchangée et a toujours demandé une réponse à une invite Oui / Non / Annuler. Le titre a été mis à jour pour être plus clair que mon original, mais la description de la question était toujours claire (à mon avis).
Myrddin Emrys
165
Vous pouvez utiliser la commande de lecture intégrée ; Utilisez l' -poption pour inviter l'utilisateur à poser une question.
Depuis BASH4, vous pouvez maintenant utiliser -ipour 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" -epour 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 ~/
Il convient de noter que FILEPATHc'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, vlcouvrirait ce fichier.
Ken Sharp
Quel est l'avantage du -edeuxième exemple (simple oui / non)?
JBallin
Une raison d'utiliser -e -pau lieu de -ep?
JBallin
1
Sans l' -eindicateur / 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.
+1 Solution génialement simple. Seule chose: cela vous demandera et promettra et vous invitera ... jusqu'à ce que vous ajoutiez un exitintérieur :)
kaiser
5
(kaiser: Pour rompre avec cela, entrez simplement l'EOT:. Ctrl-DMais bien sûr, le vrai code qui l'utilise aura besoin d'une pause ou d'une sortie dans le corps.)
Zorawar
12
Cependant, cela ne vous permettra pas d'entrer o ou n. Vous choisissez en entrant 1 2 ou 3.
djjeck
3
exitquittera le script tous ensemble, breakne quittera que la boucle dans laquelle vous vous trouvez (si vous êtes sur une boucle whileou case)
wranvaud
58
read -p "Are you alright? (y/n) " RESP
if["$RESP"="y"];then
echo "Glad to hear it"else
echo "You need more bash programming"fi
Mettez quatre espaces au début de chaque ligne pour conserver la mise en forme du code.
Jouni K. Seppänen
10
Pourquoi nous fournissons «y» et «n» comme paramètres pour demander () si les commutateurs de cas sont codés en dur? Cela demande simplement une mauvaise utilisation. Ce sont des paramètres fixes, non modifiables, donc l'écho sur la ligne 2 doit se lire: echo -n "$ 1 [O / N]?" Ils ne peuvent pas être modifiés, ils ne doivent donc pas être fournis.
Myrddin Emrys
1
@MyrddinEmrys Pourriez-vous s'il vous plaît élaborer votre commentaire? Ou postez un lien vers un article ou quelques mots clés afin que je puisse faire des recherches par moi-même.
Mateusz Piotrowski
4
@MateuszPiotrowski La réponse a été modifiée et améliorée depuis que j'ai fait mon commentaire. Vous pouvez cliquer sur le lien «modifié le 23 décembre» ci-dessus pour afficher toutes les versions antérieures de cette réponse. En 2008, le code était assez différent.
Myrddin Emrys
27
Tu veux:
Commandes intégrées Bash (c'est-à-dire portables)
Vérifiez TTY
Réponse par défaut
Temps libre
Question colorée
Fragment
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_xxxxif[[ $do_xxxx =~^(y|Y|)$ ]]# Do if 'y' or 'Y' or emptythen
xxxx
fi
@Jav l'écho imprime une nouvelle ligne après votre réponse. Sans cela, la prochaine chose à imprimer apparaîtrait immédiatement après votre réponse sur la même ligne. Essayez de retirer le echopour voir par vous-même.
Dennis
13
Pour obtenir une jolie boîte de saisie de type ncurses, utilisez la boîte de dialogue de commande comme ceci:
#!/bin/bashif(dialog --title "Message"--yesno "Want to do something risky?"625)# message box will have the size 25x6 charactersthen
echo "Let's do something risky"# do something riskyelse
echo "Let's stay boring"fi
Le package de dialogue est installé par défaut au moins avec SUSE Linux. Ressemble à:
yap, -e-ine fonctionne pas dans sh (Bourne shell), mais la question est taguée bash spécifiquement ..
Jahid
12
Vous pouvez utiliser la valeur par défaut REPLYsur 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 answercase"$yn"in# match only work with the character class from the expression
${yesexpr##^}) echo "answer $yesstr" ;;
${noexpr##^}) echo "answer $nostr" ;;esac
Les mots clés yesstret nostrlocale et les éléments YESSTRet NOSTRlanginfo étaient auparavant utilisés pour faire correspondre les réponses affirmatives et négatives des utilisateurs. En POSIX.1-2008, le yesexpr, noexpr, YESEXPR, et les NOEXPRexpressions 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:
J'adore l'ajout d'une option indépendante de la langue. Bien joué.
Myrddin Emrys
1
Malheureusement, POSIX ne spécifie que les deux premiers (yesexpr et noexpr). Sur Ubuntu 16, yesstr et nostr sont vides.
Urhixidur
1
Mais attendez! Il y a de pires nouvelles! Les expressions de l'instruction bash case ne sont pas régulières, ce sont des expressions de nom de fichier. Ainsi, yesexpr et noexpr d'Ubuntu 16 ("^ [yY]. *" Et "^ [nN]. *", Respectivement) échoueront complètement en raison de la période incorporée. Dans une expression régulière, ". *" Signifie "tout caractère autre qu'un saut de ligne, zéro ou plusieurs fois". Mais dans une déclaration de cas, c'est un "." suivi d'un nombre quelconque de caractères.
Urhixidur
1
Enfin, le meilleur qui peut être fait avec yesexpret noexprdans 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
Léa Gris
10
Touche unique uniquement
Voici une approche plus longue, mais réutilisable et modulaire:
Renvoie 0= oui et 1= non
Aucune pression sur entrée requise - juste un seul caractère
Peut appuyer enterpour accepter le choix par défaut
Peut désactiver le choix par défaut pour forcer une sélection
Fonctionne pour les deux zsh et bash.
Par défaut à "non" lorsque vous appuyez sur Entrée
Notez que le Nest en majuscule. Ici, appuyez sur Entrée, en acceptant la valeur par défaut:
Ci-dessus, je viens d'appuyer sur Entrée, donc la commande s'est exécutée.
Pas de valeur par défaut enter- exiger youn
$ 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, 1ou faux a été retourné. Notez qu'avec cette fonction de niveau inférieur, vous devrez fournir la vôtre[y/n]? invite.
Code
# 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 defualtingfunction 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 entercase"$REPLY"in
Y|y)return0;;
N|n)return1;;'')[[ $enter_return ]]&&return"$enter_return"esacdone}# 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}
Quand j'ai testé ce script, au lieu de la sortie ci-dessus, j'ai eu, Show dangerous command [y/N]? [y/n]?etShow dangerous command [Y/n]? [y/n]?
Ilias Karim
Merci @IliasKarim, j'ai corrigé cela tout à l'heure.
Tom Hale
9
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/ttyfonctionne bien pour moi:
echo -n "These files will be uploaded. Is this ok? (y/n) "
read yesno </dev/tty
if["x$yesno"="xy"];then# Yeselse# Nofi
Une partie importante de cela est la validation des entrées. Je pense que l'adaptation de mon premier exemple pour accepter l' ttyentré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).
Myrddin Emrys
7
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:
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.
Une façon simple de le faire est avec xargs -pou 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.)
Pas mal, mais xargs --interactivese 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.
Myrddin Emrys
Je vois. Ma pensée était que «annuler» signifiait simplement arrêter toute autre exécution, ce que cela prend en charge via Ctrl-C, mais si vous avez besoin de faire quelque chose de plus complexe sur annuler (ou sur non), cela ne suffira pas.
Joshua Goldberg
3
En tant qu'ami d'une commande d'une ligne, j'ai utilisé ce qui suit:
Pouvez-vous clarifier l'utilisation de la variable d'invite? Il me semble qu'il est essuyé après la doublure, alors comment utilisez-vous la ligne pour faire quoi que ce soit?
Myrddin Emrys
l'invite est effacée après la boucle while. Parce que je veux que la variable d'invite soit initialisée par la suite (puisque j'utilise l'instruction plus souvent). Avoir cette ligne dans un script shell ne se poursuivra que si y | Y est tapé et quittera si n | N est tapé ou répétez la demande d'entrée pour tout le reste.
ccDict
3
J'ai utilisé la casedéclaration plusieurs fois dans un tel scénario, en utilisant la déclaration de cas est une bonne façon de procéder. Une whileboucle, qui résume le casebloc, 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 breakpeut ê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: caseinstruction et whileboucle possible .
Exemple d'utilisation d'une casedé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
Cela semble complexe et fragile. Que diriez-vous de justeyn(){ read -s -n 1 -p '[y/n]'; test "$REPLY" = "y" ; } yn && echo success || echo failure
tripleee
2
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.";;esacdone
echo -e "\nAnswer = $ans"if[["${ans,,}"=="q"]];then
echo "OK Quitting, we will assume that he is"
exit 0fiif[["${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/43532read
commande pour demanderRé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:Une autre méthode, soulignée par Steven Huwig , est le
select
commandement de Bash . Voici le même exemple d'utilisationselect
: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écessairewhile 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:
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 .
la source
exit
pour nebreak
pas fermer l'onglet lorsque j'ai sélectionné «non».break
dansselect
s'il n'y a pas de boucle?Au moins cinq réponses pour une question générique.
Cela dépend de
et si tu veux
1. Solutions génériques POSIX
Vous pouvez utiliser la
read
commande, suivie deif ... then ... else
:(Merci au commentaire d'Adam Katz : remplacement du test ci-dessus par un test plus portable et évitant une fourche :)
POSIX, mais fonctionnalité clé unique
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 .)
Remarque: cela a été testé soussh, frapper, ksh, tiret et occupé!
Idem, mais en attendant explicitement you n:
Utiliser des outils dédiés
Il existe de nombreux outils qui ont été construits en utilisant
libncurses
,libgtk
,libqt
ou d' autres bibliothèques graphiques. Par exemple, en utilisantwhiptail
:Selon votre système, vous devrez peut-être le remplacer
whiptail
par un autre outil similaire:où
20
est la hauteur de la boîte de dialogue en nombre de lignes et la60
largeur de la boîte de dialogue. Ces outils ont tous presque la même syntaxe.2. Solutions spécifiques à Bash
Méthode de base en ligne
Je préfère utiliser
case
pour pouvoir même testeryes | ja | si | oui
si besoin ...en ligne avec une caractéristique clé unique
Sous bash, nous pouvons spécifier la longueur de l'entrée prévue pour la
read
commande:Sous bash, la
read
commande accepte un paramètre de délai d'attente , ce qui pourrait être utile.3. Quelques astuces pour des outils dédiés
Des boîtes de dialogue plus sophistiquées, au-delà de simples
yes - no
objectifs:Barre de progression:
Petite démo:
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
5. Utilisation de l'historique de readline
Exemple:
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.la source
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 nonstty -sane
.read answer
interprétera les barres obliques inverses avant les espaces et les sauts de ligne, et les supprimera autrement, ce qui est rarement prévu. Utilisez à laread -r answer
place selon SC2162 .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ôtreecho "$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 supprimerY
ouy
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.).la source
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:(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:
la source
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écutervlc "$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.
la source
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 bouclewhile
oucase
)la source
Voici quelque chose que j'ai mis en place:
Je suis un débutant, alors prenez ceci avec un grain de sel, mais cela semble fonctionner.
la source
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
pourcase "${yn:-Y}"
avoir oui par défautla source
Tu veux:
Fragment
Explications
[[ -t 0 ]] && read ...
=> Appeler la commanderead
si TTYread -n 1
=> Attendez un caractère$'\e[1;32m ... \e[0m '
=> Imprimer en vert(le vert est bien car lisible sur les deux fonds blanc / noir)
[[ $do_xxxx =~ ^(y|Y|)$ ]]
=> expression bashDélai d'attente => La réponse par défaut est Non
la source
La façon la plus simple d'y parvenir avec le moins de lignes est la suivante:
Le
if
est juste un exemple: il est à vous comment gérer cette variable.la source
Utilisez la
read
commande:puis toutes les autres choses dont vous avez besoin
la source
Cette solution lit un seul caractère et appelle une fonction sur une réponse oui.
la source
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:
Le package de dialogue est installé par défaut au moins avec SUSE Linux. Ressemble à:
la source
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:
-i
option imprime une entrée suggestive.la source
-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 aread
, convertir en minuscules et comparer à un ensemble de variables avec une expression.Le script prend également en charge
ja
/si
/oui
la source
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 du
LC_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.EDIT: Comme @Urhixidur mentionné dans son commentaire :
Voir: https://www.ee.ryerson.ca/~courses/ele709/susv4/xrat/V4_xbd_chap07.html#tag_21_07_03_06
Vous pouvez également utiliser les paramètres régionaux de la manière Bash:
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:la source
yesexpr
etnoexpr
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
Touche unique uniquement
Voici une approche plus longue, mais réutilisable et modulaire:
0
= oui et1
= nonzsh
etbash
.Par défaut à "non" lorsque vous appuyez sur Entrée
Notez que le
N
est en majuscule. Ici, appuyez sur Entrée, en acceptant la valeur par défaut: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:
Par défaut "oui" lorsque vous appuyez sur Entrée
Notez que le
Y
est en majuscule:Ci-dessus, je viens d'appuyer sur Entrée, donc la commande s'est exécutée.
Pas de valeur par défaut enter- exiger
y
oun
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.Code
la source
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:J'espère que cela aide quelqu'un.
la source
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:
Cette méthode a été publiée dans l'espoir que quelqu'un puisse la trouver utile et gagner du temps.
la source
Version à choix multiples:
Exemple:
Il sera défini
REPLY
sury
(à l'intérieur du script).la source
Je vous suggère d' utiliser la boîte de dialogue ...
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.
la source
Inspiré par les réponses de @Mark et @Myrddin, j'ai créé cette fonction pour une invite universelle
utilisez-le comme ceci:
la source
plus générique serait:
la source
Une façon simple de le faire est avec
xargs -p
ou gnuparallel --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,
la source
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:
Forme longue écrite, cela fonctionne comme ceci:
la source
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. Unewhile
boucle, qui résume lecase
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, unbreak
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 etwhile
boucle possible .Exemple d'utilisation d'une
case
déclaration pour répondre à votre demandela source
Oui / Non / Annuler
Une fonction
Usage
Confirmer avec une entrée utilisateur propre
Une fonction
Usage
la source
la source
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.
la source
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!
la source