Wie fordere ich die Eingabe von Ja / Nein / Abbrechen in einem Linux-Shell-Skript auf?
1443
Ich möchte die Eingabe in einem Shell-Skript anhalten und den Benutzer zur Auswahl auffordern.
Der Standard Yes, Nooder CancelTyp Frage.
Wie erreiche ich dies in einer typischen Bash-Eingabeaufforderung?
Nur als Hinweis: Die Konvention für Eingabeaufforderungen ist so, dass, wenn Sie eine [yn]Option präsentieren, die aktivierte Option standardmäßig aktiviert ist, dh [Yn]standardmäßig "Ja" und [yN]standardmäßig "Nein". Siehe ux.stackexchange.com/a/40445/43532
Tyzoid
Jeder, der von ZSH hierher kommt, sieht in dieser Antwort, wie man den readBefehl zur Eingabeaufforderung verwendet
smac89
Antworten:
1618
Die einfachste und am weitesten verbreitete Methode, um Benutzereingaben an einer Shell-Eingabeaufforderung abzurufen, ist der readBefehl. Der beste Weg, um seine Verwendung zu veranschaulichen, ist eine einfache Demonstration:
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
echo "Do you wish to install this program?"
select yn in"Yes""No";docase $yn inYes) make install;break;;No) exit;;esacdone
Mit selectSie nicht brauchen die Eingabe zu sanieren - es zeigt die verfügbaren Optionen, und Sie eine Nummer eingeben , um Ihre Auswahl entspricht. Es wird auch automatisch while truewiederholt , sodass keine Wiederholung erforderlich ist, wenn eine ungültige Eingabe erfolgt.
Außerdem hat Léa Gris in ihrer Antwort einen Weg aufgezeigt, die Anforderungssprache agnostisch zu machen . Die Anpassung meines ersten Beispiels, um mehrere Sprachen besser bedienen zu können, könnte folgendermaßen aussehen:
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
Offensichtlich bleiben andere Kommunikationszeichenfolgen hier unübersetzt (Installieren, Antworten), die in einer vollständigeren Übersetzung behandelt werden müssten, aber in vielen Fällen wäre sogar eine teilweise Übersetzung hilfreich.
Bei Verwendung von Bash in OS X Leopard habe ich geändert exit, breakum das Schließen der Registerkarte zu verhindern, wenn ich "Nein" ausgewählt habe.
Trey Piepmeier
1
Wie funktioniert dies mit Optionen, die länger als Ja oder Nein sind? Schreiben Sie in der case-Klausel etwas wie: Programm installieren und danach nichts tun) make install; brechen;
Shawn
1
@Shawn Mit read können Sie natürlich jedes Glob- oder Regex-Muster verwenden, das von der switch-Anweisung der Bash-Shell unterstützt wird. Es passt nur den eingegebenen Text an Ihre Muster an, bis eine Übereinstimmung gefunden wird. Mit select wird die Liste der Auswahlmöglichkeiten für den Befehl angegeben und dem Benutzer angezeigt. Sie können festlegen, dass die Elemente in der Liste so lang oder so kurz sind, wie Sie möchten. Ich empfehle, auf den Manpages nach umfassenden Nutzungsinformationen zu suchen.
Myrddin Emrys
3
Warum gibt es eine breakin der, selectwenn es keine Schleife gibt?
Jayen
1
@akostadinov Ich sollte wirklich meinen Bearbeitungsverlauf mehr lesen. Sie haben Recht, ich liege falsch, und ich habe einen Fehler eingeführt, der Jayans Rat folgt, hah. Der Fehler wurde später behoben, aber die Änderungen waren so weit voneinander entfernt, dass ich mich nicht einmal daran erinnerte, ihn geändert zu haben.
Myrddin Emrys
526
Mindestens fünf Antworten für eine allgemeine Frage.
Es hängt davon ab
posix konform: könnte auf schlechten Systemen mit generischen arbeiten Schale Umgebungen
(Dank an Adam Katz 'Kommentar : Ersetzte den obigen Test durch einen, der tragbarer ist und eine Gabel vermeidet :)
POSIX, aber Single Key-Funktion
Aber wenn Sie nicht möchten, dass der Benutzer schlagen muss Return, können Sie schreiben:
( Bearbeitet: Wie @JonathanLeffler zu Recht vorschlägt, könnte es besser sein, die Konfiguration von stty zu speichern , als sie einfach zu zwingen, gesund zu werden .)
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
Verwenden dedizierter Tools
Es gibt viele Tools , die mit gebaut wurden libncurses, libgtk, libqtoder andere grafische Bibliotheken. Zum Beispiel mit whiptail:
if whiptail --yesno "Is this a good question"2060;then
echo Yeselse
echo Nofi
Abhängig von Ihrem System müssen Sie möglicherweise ein whiptailanderes ähnliches Tool ersetzen :
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
Dabei 20ist die Höhe des Dialogfelds in Anzahl der Zeilen und 60die Breite des Dialogfelds angegeben. Diese Tools haben alle nahezu dieselbe Syntax.
read -p "Is this a good question (y/n)? " answer
case ${answer:0:1}in
y|Y )
echo Yes;;*)
echo No;;esac
Ich bevorzuge die Verwendung, casedamit ich yes | ja | si | ouibei Bedarf sogar testen kann ...
im Einklang mit einzelnem Schlüsselmerkmal
Unter bash können wir die Länge der beabsichtigten Eingabe für den readBefehl angeben :
read -n 1-p "Is this a good question (y/n)? " answer
Unter bash readakzeptiert der Befehl einen Timeout- Parameter, der nützlich sein kann.
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. Einige Tricks für spezielle Tools
Anspruchsvollere Dialogfelder, die über einfache yes - noZwecke hinausgehen :
dialog --menu "Is this a good question"206012 y Yes n No m Maybe
Fortschrittsanzeige:
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)
Kleine Demo:
#!/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
Dadurch wird eine Datei erstellen .myscript.historyin Ihrem $HOMEVerzeichnis, als Sie Readline- Geschichte Befehle, wie nutzen könnten Up, Down, Ctrl+ rund andere.
Beachten Sie, dass dies sttydie -gOption zur Verwendung bietet : old_stty=$(stty -g); stty raw -echo; …; stty "$old_stty". Dadurch wird die Einstellung genau so wiederhergestellt, wie sie gefunden wurde. Dies kann mit der Einstellung identisch sein oder nicht stty -sane.
Jonathan Leffler
3
read answerinterpretiert Backslashes vor Leerzeichen und Zeilenvorschüben und entfernt sie ansonsten, was selten beabsichtigt ist. Verwenden Sie read -r answerstattdessen gemäß SC2162 .
vlfig
1
Die Methode "Verwenden der Readline-Historie" ist für die Frage des OP so schrecklich ungeeignet. Ich bin froh, dass du es trotzdem aufgenommen hast. Ich habe Dutzende viel komplizierterer Skripte, die ich mit diesem Muster aktualisieren möchte!
Bruno Bronosky
5
Sie können sowohl casefür POSIX als auch für Bash verwenden (verwenden Sie eine Platzhalterbedingung anstelle einer Bash-Teilzeichenfolge :) case $answer in; [Yy]* ) echo Yes ;;, aber ich bevorzuge stattdessen die Verwendung einer bedingten Anweisung, die [ "$answer" != "${answer#[Yy]}" ]Ihre bevorzugt echo "$answer" | grep -iq ^y. Es ist portabler (einige Nicht-GNU-Greps werden nicht -qkorrekt implementiert ) und hat keinen Systemaufruf. ${answer#[Yy]}Verwendet die Parametererweiterung zum Entfernen Yoder yvon Anfang an $answerund verursacht eine Ungleichung, wenn eine der beiden vorhanden ist. Dies funktioniert in jeder POSIX-Shell (Dash, Ksh, Bash, Zsh, Busybox usw.).
Adam Katz
1
@CarterPape Ja, das war ein Witz! Aber in dieser detaillierten Antwort finden Sie möglicherweise viele Tipps (zweiter Punkt enthält mindestens 3 verschiedene Methoden)! Und ... ab ca. 5 Jahren erzählen Sie zuerst von meiner Zählmethode! ;-))
F. Hauri
349
echo "Please enter some input: "
read input_variable
echo "You entered: $input_variable"
Ich bin anderer Meinung, da nur ein Teil der Funktionalität des Dialogfelds "Ja, Nein, Abbrechen" in DOS implementiert wird. Der Teil, den es nicht implementiert, ist die Eingabeprüfung ... Schleife, bis eine gültige Antwort empfangen wird.
Myrddin Emrys
1
(Der ursprüngliche
Fragentitel
8
Die ursprüngliche Beschreibung der Frage bleibt jedoch unverändert und wird immer um eine Antwort auf eine Ja / Nein / Abbrechen-Eingabeaufforderung gebeten. Der Titel wurde aktualisiert, um klarer als mein ursprünglicher zu sein, aber die Beschreibung der Frage war immer klar (meiner Meinung nach).
Myrddin Emrys
165
Sie können im internen Verwendung Lesebefehl;Verwenden Sie die -pOption, um den Benutzer mit einer Frage aufzufordern.
Seit BASH4 können Sie jetzt -ieine Antwort vorschlagen:
read -e -p "Enter the path to the file: "-i "/usr/local/etc/" FILEPATH
echo $FILEPATH
(Denken Sie jedoch daran, die Option "readline" -ezu verwenden, um die Zeilenbearbeitung mit den Pfeiltasten zu ermöglichen.)
Wenn Sie eine "Ja / Nein" -Logik wünschen, können Sie Folgendes tun:
read -e -p "
List the content of your home dir ? [Y/n] " YN
[[ $YN =="y"|| $YN =="Y"|| $YN ==""]]&& ls -la ~/
Es ist zu beachten, dass dies FILEPATHder von Ihnen gewählte Variablenname ist und mit der Antwort auf die Eingabeaufforderung festgelegt wird. Wenn Sie dann beispielsweise ausführen würden vlc "$FILEPATH", vlcwürde diese Datei geöffnet.
Ken Sharp
Was ist der Vorteil -eim zweiten Beispiel (einfaches Ja / Nein)?
JBallin
Gibt es einen Grund, -e -panstatt zu verwenden -ep?
JBallin
1
Ohne das -eFlag / die Option können Sie (abhängig von der Implementierung) möglicherweise nicht "y" eingeben und dann Ihre Meinung ändern und durch ein "n" (oder irgendetwas anderes) ersetzen. Wenn Sie einen Befehl dokumentieren, ist es unter anderem aus Gründen der Lesbarkeit / Klarheit besser, die Optionen separat aufzulisten.
+1 Genial einfache Lösung. Einzige Sache: Dies wird auffordern und auffordern und auffordern ... bis Sie ein exitInside hinzufügen :)
Kaiser
5
(kaiser: Um davon abzubrechen, geben Sie einfach die EOT ein: Ctrl-DAber natürlich benötigt echter Code, der ihn verwendet, eine Unterbrechung oder einen Ausgang im Körper.)
Zorawar
12
Dies erlaubt Ihnen jedoch nicht, y oder n einzugeben. Sie wählen, indem Sie 1 2 oder 3
eingeben
3
exitwird das Skript alle zusammen breakwhilecase
beenden
57
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
Fügen Sie am Anfang jeder Zeile vier Leerzeichen ein, um die Formatierung des Codes beizubehalten.
Jouni K. Seppänen
10
Warum geben wir 'y' und 'n' als Parameter an, um abzufragen (), ob die Fallschalter fest codiert sind? Das bittet nur um Missbrauch. Da es sich um feste Parameter handelt, die nicht geändert werden können, sollte das Echo in Zeile 2 lauten: echo -n "$ 1 [J / N]?" Sie können nicht geändert werden, daher sollten sie nicht geliefert werden.
Myrddin Emrys
1
@MyrddinEmrys Könnten Sie bitte Ihren Kommentar ausarbeiten? Oder poste einen Link zu einem Artikel oder ein paar Keywords, damit ich selbst recherchieren kann.
Mateusz Piotrowski
4
@MateuszPiotrowski Die Antwort wurde bearbeitet und verbessert, seit ich meinen Kommentar abgegeben habe. Sie können oben auf den Link "bearbeitet am 23. Dezember" klicken, um alle früheren Versionen dieser Antwort anzuzeigen. Im Jahr 2008 war der Code ganz anders.
Myrddin Emrys
27
Sie wollen:
Bash eingebaute Befehle (dh portabel)
Überprüfen Sie TTY
Standardantwort
Auszeit
Farbige Frage
Snippet
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 das Echo druckt nach Ihrer Antwort eine neue Zeile. Ohne sie wird das nächste zu druckende Element unmittelbar nach Ihrer Antwort in derselben Zeile angezeigt. Entfernen Sie das echo, um sich selbst davon zu überzeugen.
Dennis
13
Eine schöne ncurses-like inputbox Verwenden Sie den Befehl erhalten Dialog wie folgt aus :
#!/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
Das Dialogpaket wird standardmäßig mindestens unter SUSE Linux installiert. Sieht aus wie:
yap, -e-iarbeite nicht in sh (Bourne Shell), aber die Frage ist Bash spezifisch markiert.
Jahid
12
Sie können die Standardeinstellung REPLYfür a verwenden read, in Kleinbuchstaben konvertieren und mit einer Reihe von Variablen mit einem Ausdruck vergleichen.
Das Skript unterstützt auch 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
Es ist möglich, eine länderbezogene "Ja / Nein-Auswahl" in einer POSIX-Shell zu verarbeiten. Mithilfe der Einträge der LC_MESSAGESGebietsschemakategorie stellt witch vorgefertigte RegEx-Muster bereit, die mit einer Eingabe übereinstimmen, sowie Zeichenfolgen für das lokalisierte Ja Nein.
#!/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
Die Schlüsselwörter yesstrund nostrlocale sowie die Elemente YESSTRund NOSTRlanginfo wurden früher verwendet, um positive und negative Antworten des Benutzers abzugleichen. In POSIX.1-2008, die yesexpr, noexpr, YESEXPR, und NOEXPRerweiterte reguläre Ausdrücke haben sie ersetzt. Anwendungen sollten die allgemeinen, auf dem Gebietsschema basierenden Nachrichtenfunktionen verwenden, um Aufforderungsnachrichten auszugeben, die Beispielantworten enthalten.
Alternativ können Sie Gebietsschemas auf Bash-Weise verwenden:
Ich liebe die Hinzufügung einer sprachunabhängigen Option. Gut gemacht.
Myrddin Emrys
1
Leider gibt POSIX nur die ersten beiden an (yesexpr und noexpr). Unter Ubuntu 16 sind yesstr und nostr leer.
Urhixidur
1
Aber warte! Es gibt schlimmere Neuigkeiten! Die Bash-Case-Anweisungsausdrücke sind nicht regulär, sondern Dateinamenausdrücke. Yesexpr und noexpr von Ubuntu 16 ("^ [yY]. *" Und "^ [nN]. *") Werden daher aufgrund der eingebetteten Periode völlig fehlschlagen. In einem regulären Ausdruck bedeutet ". *" "Jedes Nicht-Zeilenumbruchzeichen, null oder mehrmals". Aber in einer Fallaussage ist es ein wörtliches "." gefolgt von einer beliebigen Anzahl von Zeichen.
Urhixidur
1
Das Beste, was mit yesexprund noexprin einer Shell-Umgebung gemacht werden kann, ist, es in Bashs spezifischem RegEx-Matching zu verwendenif [[ "$yn" =~ $yesexpr ]]; then echo $"Answered yes"; else echo $"Answered no"; fi
Léa Gris
10
Nur ein Tastendruck
Hier ist ein längerer, aber wiederverwendbarer und modularer Ansatz:
Rückgabe 0= ja und 1= nein
Kein Drücken der Eingabetaste erforderlich - nur ein einzelnes Zeichen
Kann drücken enter, um die Standardauswahl zu akzeptieren
Kann die Standardauswahl deaktivieren, um eine Auswahl zu erzwingen
Funktioniert für beide zshund bash.
Standardmäßig "Nein", wenn Sie die Eingabetaste drücken
Beachten Sie, dass das Ngroß geschrieben ist. Hier wird die Eingabetaste gedrückt, wobei die Standardeinstellung übernommen wird:
Oben habe ich nur die Eingabetaste gedrückt, sodass der Befehl ausgeführt wurde.
Kein Standard ein enter- erfordern yodern
$ 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
Hier 1oder falsch wurde zurückgegeben. Beachten Sie, dass Sie mit dieser untergeordneten Funktion Ihre eigenen Funktionen bereitstellen müssen[y/n]? Eingabeaufforderung .
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}
Als ich dieses Skript getestet habe, habe ich anstelle des obigen Oututs Show dangerous command [y/N]? [y/n]?undShow dangerous command [Y/n]? [y/n]?
Ilias Karim
Danke @IliasKarim, das habe ich gerade behoben.
Tom Hale
9
Entschuldigung für die Veröffentlichung in einem so alten Beitrag. Vor einigen Wochen hatte ich ein ähnliches Problem. In meinem Fall brauchte ich eine Lösung, die auch in einem Online-Installationsskript funktioniert, z.curl -Ss https://raw.github.com/_____/installer.sh | bash
Verwenden read yesno < /dev/ttyfunktioniert gut für mich:
echo -n "These files will be uploaded. Is this ok? (y/n) "
read yesno </dev/tty
if["x$yesno"="xy"];then# Yeselse# Nofi
Ein wichtiger Teil davon ist die Eingabevalidierung. Ich denke, mein erstes Beispiel so anzupassen, dass ttyEingaben akzeptiert werden, wie Sie es getan haben, hätte sich auch für Sie bewährt und auch Schleifen bei schlechten Eingaben erhalten (stellen Sie sich ein paar Zeichen im Puffer vor; Ihre Methode würde den Benutzer zwingen, immer Nein zu wählen).
Myrddin Emrys
7
Mir ist aufgefallen, dass niemand eine Antwort mit einem mehrzeiligen Echo-Menü für solch einfache Benutzereingaben gepostet hat.
Der Dialogbefehl ermöglicht die Verwendung von Fensterfeldern in Shell-Skripten, um deren Verwendung interaktiver zu gestalten.
Es ist einfach und benutzerfreundlich. Es gibt auch eine Gnome-Version namens gdialog, die genau dieselben Parameter verwendet, aber den GUI-Stil auf X zeigt.
Eine einfache Möglichkeit, dies zu tun, ist mit xargs -poder gnu parallel --interactive.
Ich mag das Verhalten von xargs ein wenig besser, weil es jeden Befehl unmittelbar nach der Eingabeaufforderung wie andere interaktive Unix-Befehle ausführt, anstatt die Yesses zu sammeln, die am Ende ausgeführt werden sollen. (Sie können Strg-C drücken, nachdem Sie die gewünschten durchlaufen haben.)
Nicht schlecht, aber xargs --interactivebeschränkt auf Ja oder Nein. Solange das alles ist, was Sie brauchen, kann das genug sein, aber meine ursprüngliche Frage gab ein Beispiel mit drei möglichen Ergebnissen. Ich mag es wirklich, dass es streambar ist; Viele gängige Szenarien würden von der Fähigkeit zur Weiterleitung profitieren.
Myrddin Emrys
Aha. Meiner Meinung nach sollte "Abbrechen" einfach jede weitere Ausführung stoppen, was dies über Strg-C unterstützt. Wenn Sie jedoch beim Abbrechen (oder bei Nein) etwas Komplexeres tun müssen, reicht dies nicht aus.
Joshua Goldberg
3
Als Freund eines einzeiligen Befehls habe ich Folgendes verwendet:
Können Sie die Verwendung der Eingabeaufforderungsvariablen verdeutlichen? Sieht für mich so aus, als wäre es nach dem einen Liner abgewischt. Wie benutzt man die Linie also, um etwas zu tun?
Myrddin Emrys
Die Eingabeaufforderung wird nach der while-Schleife gelöscht. Weil ich möchte, dass die Eingabeaufforderungsvariable anschließend initialisiert wird (da ich die Anweisung häufiger verwende). Wenn diese Zeile in einem Shell-Skript enthalten ist, wird nur fortgefahren, wenn y | Y eingegeben wird, und beendet, wenn n | N eingegeben wird, oder es wird wiederholt nach der Eingabe für alles andere gefragt.
ccDict
3
Ich habe die caseAussage in einem solchen Szenario ein paar Mal verwendet. Die Verwendung der Fallanweisung ist ein guter Weg, um dies zu erreichen. Eine whileSchleife, die den caseBlock kapselt und eine boolesche Bedingung verwendet, kann implementiert werden, um das Programm noch besser steuern zu können und viele andere Anforderungen zu erfüllen. Nachdem alle Bedingungen erfüllt sind, breakkann ein verwendet werden, das die Steuerung an den Hauptteil des Programms zurückgibt. Um andere Bedingungen zu erfüllen, können natürlich auch bedingte Anweisungen hinzugefügt werden, die die Kontrollstrukturen begleiten: caseAnweisung und mögliche whileSchleife.
Beispiel für die Verwendung einer caseAnweisung zur Erfüllung Ihrer Anfrage
#! /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
Dies scheint komplex und fragil. Wie wäre es nuryn(){ read -s -n 1 -p '[y/n]'; test "$REPLY" = "y" ; } yn && echo success || echo failure
Tripleee
2
Als Antwort auf andere:
Sie müssen in BASH4 keine Groß- und Kleinschreibung angeben. Verwenden Sie einfach das ',,', um eine var-Kleinbuchstabe zu erstellen. Außerdem mag ich es nicht, Code in den Leseblock zu setzen, das Ergebnis zu erhalten und außerhalb des Leseblocks IMO damit umzugehen. Fügen Sie auch ein 'q' ein, um IMO zu beenden. Zuletzt, warum 'Ja' eingeben, einfach -n1 verwenden und y drücken.
Beispiel: Der Benutzer kann y / n und auch q drücken, um einfach zu beenden.
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
In solchen Szenarien müssen Sie das Skript meistens so lange ausführen, bis der Benutzer weiterhin "Ja" eingibt, und erst dann anhalten, wenn der Benutzer "Nein" eingibt. Das folgende Snippet würde Ihnen dabei helfen!
#!/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 präsentieren, die aktivierte Option standardmäßig aktiviert ist, dh[Yn]
standardmäßig "Ja" und[yN]
standardmäßig "Nein". Siehe ux.stackexchange.com/a/40445/43532read
Befehl zur Eingabeaufforderung verwendetAntworten:
Die einfachste und am weitesten verbreitete Methode, um Benutzereingaben an einer Shell-Eingabeaufforderung abzurufen, ist der
read
Befehl. Der beste Weg, um seine Verwendung zu veranschaulichen, ist eine einfache Demonstration:Ein anderes Verfahren, wies darauf hin , durch Steven Huwig , ist Bash -
select
Befehl. Hier ist das gleiche Beispiel mitselect
:Mit
select
Sie nicht brauchen die Eingabe zu sanieren - es zeigt die verfügbaren Optionen, und Sie eine Nummer eingeben , um Ihre Auswahl entspricht. Es wird auch automatischwhile true
wiederholt , sodass keine Wiederholung erforderlich ist, wenn eine ungültige Eingabe erfolgt.Außerdem hat Léa Gris in ihrer Antwort einen Weg aufgezeigt, die Anforderungssprache agnostisch zu machen . Die Anpassung meines ersten Beispiels, um mehrere Sprachen besser bedienen zu können, könnte folgendermaßen aussehen:
Offensichtlich bleiben andere Kommunikationszeichenfolgen hier unübersetzt (Installieren, Antworten), die in einer vollständigeren Übersetzung behandelt werden müssten, aber in vielen Fällen wäre sogar eine teilweise Übersetzung hilfreich.
Zum Schluss lesen Sie bitte die ausgezeichnete Antwort von F. Hauri .
quelle
exit
,break
um das Schließen der Registerkarte zu verhindern, wenn ich "Nein" ausgewählt habe.break
in der,select
wenn es keine Schleife gibt?Mindestens fünf Antworten für eine allgemeine Frage.
Es hängt davon ab
und wenn du willst
1. Generische POSIX-Lösungen
Sie können den
read
Befehl verwenden, gefolgt vonif ... then ... else
:(Dank an Adam Katz 'Kommentar : Ersetzte den obigen Test durch einen, der tragbarer ist und eine Gabel vermeidet :)
POSIX, aber Single Key-Funktion
Aber wenn Sie nicht möchten, dass der Benutzer schlagen muss Return, können Sie schreiben:
( Bearbeitet: Wie @JonathanLeffler zu Recht vorschlägt, könnte es besser sein, die Konfiguration von stty zu speichern , als sie einfach zu zwingen, gesund zu werden .)
Hinweis: Dies wurde unter getestetSch, Bash, ksh, Strich und Busybox!
Gleich, aber explizit warten auf yoder n:
Verwenden dedizierter Tools
Es gibt viele Tools , die mit gebaut wurden
libncurses
,libgtk
,libqt
oder andere grafische Bibliotheken. Zum Beispiel mitwhiptail
:Abhängig von Ihrem System müssen Sie möglicherweise ein
whiptail
anderes ähnliches Tool ersetzen :Dabei
20
ist die Höhe des Dialogfelds in Anzahl der Zeilen und60
die Breite des Dialogfelds angegeben. Diese Tools haben alle nahezu dieselbe Syntax.2. Bash-spezifische Lösungen
Grundlegende In-Line- Methode
Ich bevorzuge die Verwendung,
case
damit ichyes | ja | si | oui
bei Bedarf sogar testen kann ...im Einklang mit einzelnem Schlüsselmerkmal
Unter bash können wir die Länge der beabsichtigten Eingabe für den
read
Befehl angeben :Unter bash
read
akzeptiert der Befehl einen Timeout- Parameter, der nützlich sein kann.3. Einige Tricks für spezielle Tools
Anspruchsvollere Dialogfelder, die über einfache
yes - no
Zwecke hinausgehen :Fortschrittsanzeige:
Kleine Demo:
Mehr Probe? Schauen Sie sich die Verwendung von Whiptail für die Auswahl des USB-Geräts und des USB-Wechselspeichers an: USBKeyChooser
5. Verwenden des Readline-Verlaufs
Beispiel:
Dadurch wird eine Datei erstellen
.myscript.history
in Ihrem$HOME
Verzeichnis, als Sie Readline- Geschichte Befehle, wie nutzen könnten Up, Down, Ctrl+ rund andere.quelle
stty
die-g
Option zur Verwendung bietet :old_stty=$(stty -g); stty raw -echo; …; stty "$old_stty"
. Dadurch wird die Einstellung genau so wiederhergestellt, wie sie gefunden wurde. Dies kann mit der Einstellung identisch sein oder nichtstty -sane
.read answer
interpretiert Backslashes vor Leerzeichen und Zeilenvorschüben und entfernt sie ansonsten, was selten beabsichtigt ist. Verwenden Sieread -r answer
stattdessen gemäß SC2162 .case
für POSIX als auch für Bash verwenden (verwenden Sie eine Platzhalterbedingung anstelle einer Bash-Teilzeichenfolge :)case $answer in; [Yy]* ) echo Yes ;;
, aber ich bevorzuge stattdessen die Verwendung einer bedingten Anweisung, die[ "$answer" != "${answer#[Yy]}" ]
Ihre bevorzugtecho "$answer" | grep -iq ^y
. Es ist portabler (einige Nicht-GNU-Greps werden nicht-q
korrekt implementiert ) und hat keinen Systemaufruf.${answer#[Yy]}
Verwendet die Parametererweiterung zum EntfernenY
odery
von Anfang an$answer
und verursacht eine Ungleichung, wenn eine der beiden vorhanden ist. Dies funktioniert in jeder POSIX-Shell (Dash, Ksh, Bash, Zsh, Busybox usw.).quelle
Sie können im internen Verwendung Lesebefehl; Verwenden Sie die
-p
Option, um den Benutzer mit einer Frage aufzufordern.Seit BASH4 können Sie jetzt
-i
eine Antwort vorschlagen:(Denken Sie jedoch daran, die Option "readline"
-e
zu verwenden, um die Zeilenbearbeitung mit den Pfeiltasten zu ermöglichen.)Wenn Sie eine "Ja / Nein" -Logik wünschen, können Sie Folgendes tun:
quelle
FILEPATH
der von Ihnen gewählte Variablenname ist und mit der Antwort auf die Eingabeaufforderung festgelegt wird. Wenn Sie dann beispielsweise ausführen würdenvlc "$FILEPATH"
,vlc
würde diese Datei geöffnet.-e
im zweiten Beispiel (einfaches Ja / Nein)?-e -p
anstatt zu verwenden-ep
?-e
Flag / die Option können Sie (abhängig von der Implementierung) möglicherweise nicht "y" eingeben und dann Ihre Meinung ändern und durch ein "n" (oder irgendetwas anderes) ersetzen. Wenn Sie einen Befehl dokumentieren, ist es unter anderem aus Gründen der Lesbarkeit / Klarheit besser, die Optionen separat aufzulisten.Bash hat wählen für diesen Zweck.
quelle
exit
Inside hinzufügen :)Ctrl-D
Aber natürlich benötigt echter Code, der ihn verwendet, eine Unterbrechung oder einen Ausgang im Körper.)exit
wird das Skript alle zusammenbreak
while
case
quelle
Folgendes habe ich zusammengestellt:
Ich bin ein Anfänger, also nimm das mit einem Körnchen Salz, aber es scheint zu funktionieren.
quelle
case $yn in
,case ${yn:-$2} in
können Sie das zweite Argument als Standardwert verwenden, Y oder N.case $yn
zu "case "${yn:-Y}"
Ja" als Standardquelle
Sie wollen:
Snippet
Erklärungen
[[ -t 0 ]] && read ...
=> Befehlread
aufrufen, wenn TTYread -n 1
=> Warte auf ein Zeichen$'\e[1;32m ... \e[0m '
=> Drucken in Grün(Grün ist in Ordnung, da es auf beiden weißen / schwarzen Hintergründen lesbar ist)
[[ $do_xxxx =~ ^(y|Y|)$ ]]
=> Bash RegexZeitüberschreitung => Standardantwort ist Nein
quelle
Der einfachste Weg, dies mit der geringsten Anzahl von Zeilen zu erreichen, ist wie folgt:
Das
if
ist nur ein Beispiel: es ist an Ihnen , wie Sie diese Variable behandeln.quelle
Verwenden Sie den
read
Befehl:und dann all die anderen Sachen, die du brauchst
quelle
Diese Lösung liest ein einzelnes Zeichen und ruft eine Funktion für eine Ja-Antwort auf.
quelle
echo
, um sich selbst davon zu überzeugen.Eine schöne ncurses-like inputbox Verwenden Sie den Befehl erhalten Dialog wie folgt aus :
Das Dialogpaket wird standardmäßig mindestens unter SUSE Linux installiert. Sieht aus wie:
quelle
Mit dieser
-e
Option kann der Benutzer die Eingabe mit den Pfeiltasten bearbeiten.Wenn Sie einen Vorschlag als Eingabe verwenden möchten:
-i
Option druckt eine suggestive Eingabe.quelle
-e
-i
arbeite nicht in sh (Bourne Shell), aber die Frage ist Bash spezifisch markiert.Sie können die Standardeinstellung
REPLY
für a verwendenread
, in Kleinbuchstaben konvertieren und mit einer Reihe von Variablen mit einem Ausdruck vergleichen.Das Skript unterstützt auch
ja
/si
/oui
quelle
Es ist möglich, eine länderbezogene "Ja / Nein-Auswahl" in einer POSIX-Shell zu verarbeiten. Mithilfe der Einträge der
LC_MESSAGES
Gebietsschemakategorie stellt witch vorgefertigte RegEx-Muster bereit, die mit einer Eingabe übereinstimmen, sowie Zeichenfolgen für das lokalisierte Ja Nein.EDIT: Wie @Urhixidur in seinem Kommentar erwähnt :
Siehe: https://www.ee.ryerson.ca/~courses/ele709/susv4/xrat/V4_xbd_chap07.html#tag_21_07_03_06
Alternativ können Sie Gebietsschemas auf Bash-Weise verwenden:
Die Antwort wird mithilfe der bereitgestellten regulären Ausdrücke der Gebietsschemaumgebung abgeglichen.
Um die verbleibenden Nachrichten zu übersetzen
bash --dump-po-strings scriptname
, geben Sie die Po-Zeichenfolgen für die Lokalisierung aus:quelle
yesexpr
undnoexpr
in einer Shell-Umgebung gemacht werden kann, ist, es in Bashs spezifischem RegEx-Matching zu verwendenif [[ "$yn" =~ $yesexpr ]]; then echo $"Answered yes"; else echo $"Answered no"; fi
Nur ein Tastendruck
Hier ist ein längerer, aber wiederverwendbarer und modularer Ansatz:
0
= ja und1
= neinzsh
undbash
.Standardmäßig "Nein", wenn Sie die Eingabetaste drücken
Beachten Sie, dass das
N
groß geschrieben ist. Hier wird die Eingabetaste gedrückt, wobei die Standardeinstellung übernommen wird:Beachten Sie auch, dass dies
[y/N]?
automatisch angehängt wurde. Das Standard "Nein" wird akzeptiert, daher wird nichts wiedergegeben.Erneut auffordern, bis eine gültige Antwort gegeben wird:
Standardmäßig "Ja", wenn Sie die Eingabetaste drücken
Beachten Sie, dass das
Y
groß geschrieben wird:Oben habe ich nur die Eingabetaste gedrückt, sodass der Befehl ausgeführt wurde.
Kein Standard ein enter- erfordern
y
odern
Hier
1
oder falsch wurde zurückgegeben. Beachten Sie, dass Sie mit dieser untergeordneten Funktion Ihre eigenen Funktionen bereitstellen müssen[y/n]?
Eingabeaufforderung .Code
quelle
Show dangerous command [y/N]? [y/n]?
undShow dangerous command [Y/n]? [y/n]?
Entschuldigung für die Veröffentlichung in einem so alten Beitrag. Vor einigen Wochen hatte ich ein ähnliches Problem. In meinem Fall brauchte ich eine Lösung, die auch in einem Online-Installationsskript funktioniert, z.
curl -Ss https://raw.github.com/_____/installer.sh | bash
Verwenden
read yesno < /dev/tty
funktioniert gut für mich:Hoffe das hilft jemandem.
quelle
tty
Eingaben akzeptiert werden, wie Sie es getan haben, hätte sich auch für Sie bewährt und auch Schleifen bei schlechten Eingaben erhalten (stellen Sie sich ein paar Zeichen im Puffer vor; Ihre Methode würde den Benutzer zwingen, immer Nein zu wählen).Mir ist aufgefallen, dass niemand eine Antwort mit einem mehrzeiligen Echo-Menü für solch einfache Benutzereingaben gepostet hat.
Diese Methode wurde in der Hoffnung veröffentlicht, dass jemand sie nützlich und zeitsparend findet.
quelle
Multiple-Choice-Version:
Beispiel:
Es wird
REPLY
aufy
(innerhalb des Skripts) gesetzt.quelle
Ich schlage vor, Sie verwenden Dialog ...
Es ist einfach und benutzerfreundlich. Es gibt auch eine Gnome-Version namens gdialog, die genau dieselben Parameter verwendet, aber den GUI-Stil auf X zeigt.
quelle
Inspiriert von den Antworten von @Mark und @Myrddin habe ich diese Funktion für eine universelle Eingabeaufforderung erstellt
benutze es so:
quelle
allgemeiner wäre:
quelle
Eine einfache Möglichkeit, dies zu tun, ist mit
xargs -p
oder gnuparallel --interactive
.Ich mag das Verhalten von xargs ein wenig besser, weil es jeden Befehl unmittelbar nach der Eingabeaufforderung wie andere interaktive Unix-Befehle ausführt, anstatt die Yesses zu sammeln, die am Ende ausgeführt werden sollen. (Sie können Strg-C drücken, nachdem Sie die gewünschten durchlaufen haben.)
z.B,
quelle
xargs --interactive
beschränkt auf Ja oder Nein. Solange das alles ist, was Sie brauchen, kann das genug sein, aber meine ursprüngliche Frage gab ein Beispiel mit drei möglichen Ergebnissen. Ich mag es wirklich, dass es streambar ist; Viele gängige Szenarien würden von der Fähigkeit zur Weiterleitung profitieren.Als Freund eines einzeiligen Befehls habe ich Folgendes verwendet:
Langform geschrieben, funktioniert es so:
quelle
Ich habe die
case
Aussage in einem solchen Szenario ein paar Mal verwendet. Die Verwendung der Fallanweisung ist ein guter Weg, um dies zu erreichen. Einewhile
Schleife, die dencase
Block kapselt und eine boolesche Bedingung verwendet, kann implementiert werden, um das Programm noch besser steuern zu können und viele andere Anforderungen zu erfüllen. Nachdem alle Bedingungen erfüllt sind,break
kann ein verwendet werden, das die Steuerung an den Hauptteil des Programms zurückgibt. Um andere Bedingungen zu erfüllen, können natürlich auch bedingte Anweisungen hinzugefügt werden, die die Kontrollstrukturen begleiten:case
Anweisung und möglichewhile
Schleife.Beispiel für die Verwendung einer
case
Anweisung zur Erfüllung Ihrer Anfragequelle
Ja / Nein / Abbrechen
Funktion
Verwendungszweck
Bestätigen Sie mit sauberen Benutzereingaben
Funktion
Verwendungszweck
quelle
quelle
yn(){ read -s -n 1 -p '[y/n]'; test "$REPLY" = "y" ; } yn && echo success || echo failure
Als Antwort auf andere:
Sie müssen in BASH4 keine Groß- und Kleinschreibung angeben. Verwenden Sie einfach das ',,', um eine var-Kleinbuchstabe zu erstellen. Außerdem mag ich es nicht, Code in den Leseblock zu setzen, das Ergebnis zu erhalten und außerhalb des Leseblocks IMO damit umzugehen. Fügen Sie auch ein 'q' ein, um IMO zu beenden. Zuletzt, warum 'Ja' eingeben, einfach -n1 verwenden und y drücken.
Beispiel: Der Benutzer kann y / n und auch q drücken, um einfach zu beenden.
quelle
In solchen Szenarien müssen Sie das Skript meistens so lange ausführen, bis der Benutzer weiterhin "Ja" eingibt, und erst dann anhalten, wenn der Benutzer "Nein" eingibt. Das folgende Snippet würde Ihnen dabei helfen!
quelle