Mindestens fünf Antworten auf eine allgemeine Frage.
Abhängig von
- posix-kompatibel:könnte auf schlechten Systemen mit generischen Shell-Umgebungen funktionieren
- Bash-spezifisch:Verwendung sogenannter Bashismen
und wenn Sie möchten
- einfache ``inline'' Frage/Antwort (allgemeine Lösungen)
- hübsch formatierte Schnittstellen, wie ncurses oder grafischere mit libgtk oder libqt...
- verwenden Sie die leistungsstarke Readline-Verlaufsfunktion
1. Generische POSIX-Lösungen
Sie könnten den read
verwenden Befehl, gefolgt von if ... then ... else
:
printf 'Is this a good question (y/n)? '
read answer
# if echo "$answer" | grep -iq "^y" ;then
if [ "$answer" != "${answer#[Yy]}" ] ;then # this grammar (the #[] operator) means that the variable $answer where any Y or y in 1st position will be dropped if they exist.
echo Yes
else
echo No
fi
(Dank des Kommentars von Adam Katz:Ersetzte den obigen Test durch einen, der tragbarer ist und eine Gabelung vermeidet:)
POSIX, aber einzelne Schlüsselfunktion
Aber wenn Sie nicht möchten, dass der Benutzer Return drücken muss , könnten Sie schreiben:
(Bearbeitet: Wie @JonathanLeffler zu Recht vorschlägt, Sparen Die Konfiguration von stty könnte besser sein, als sie einfach zu gesunden zu zwingen .)
printf '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
Hinweis: Dies wurde unter sh, bash, ksh, dash und busybox getestet!
Dasselbe, aber explizites Warten auf y oder n :
#/bin/sh
printf '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
Verwenden spezieller Tools
Es gibt viele Tools, die mit libncurses
erstellt wurden , libgtk
, libqt
oder andere grafische Bibliotheken. Verwenden Sie zum Beispiel whiptail
:
if whiptail --yesno "Is this a good question" 20 60 ;then
echo Yes
else
echo No
fi
Abhängig von Ihrem System müssen Sie möglicherweise whiptail
ersetzen mit einem anderen ähnlichen Tool:
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
wobei 20
ist die Höhe des Dialogfensters in Zeilenzahl und 60
ist die Breite des Dialogfelds. Diese Tools haben alle fast dasselbe Syntax.
DIALOG=whiptail
if [ -x /usr/bin/gdialog ] ;then DIALOG=gdialog ; fi
if [ -x /usr/bin/xdialog ] ;then DIALOG=xdialog ; fi
...
$DIALOG --yesno ...
2. Bash-spezifische Lösungen
Einfach inline Methode
read -p "Is this a good question (y/n)? " answer
case ${answer:0:1} in
y|Y )
echo Yes
;;
* )
echo No
;;
esac
Ich bevorzuge case
so konnte ich sogar auf yes | ja | si | oui
testen bei Bedarf...
an der Reihe mit Einzelschlüssel Funktion
Unter bash können wir die Länge der beabsichtigten Eingabe für read
angeben Befehl:
read -n 1 -p "Is this a good question (y/n)? " answer
Unter Bash read
Befehl akzeptiert eine Zeitüberschreitung Parameter, der nützlich sein könnte.
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 dedizierte Tools
Anspruchsvollere Dialogfelder als einfache yes - no
Zwecke:
dialog --menu "Is this a good question" 20 60 12 y Yes n No m Maybe
Fortschrittsbalken:
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
)
Kleine Demo:
#!/bin/sh
while true ;do
[ -x "$(which ${DIALOG%% *})" ] || DIALOG=dialog
DIALOG=$($DIALOG --menu "Which tool for next run?" 20 60 12 2>&1 \
whiptail "dialog boxes from shell scripts" >/dev/tty \
dialog "dialog boxes from shell with ncurses" \
gdialog "dialog boxes from shell with Gtk" \
kdialog "dialog boxes from shell with Kde" ) || exit
clear;echo "Choosed: $DIALOG."
for i in `seq 1 100`;do
date +"`printf "XXX\n%d\n%%a %%b %%T progress: %d\nXXX\n" $i $i`"
sleep .0125
done | $DIALOG --gauge "Filling the tank" 20 60 0
$DIALOG --infobox "This is a simple info box\n\nNo action required" 20 60
sleep 3
if $DIALOG --yesno "Do you like this demo?" 20 60 ;then
AnsYesNo=Yes; else AnsYesNo=No; fi
AnsInput=$($DIALOG --inputbox "A text:" 20 60 "Text here..." 2>&1 >/dev/tty)
AnsPass=$($DIALOG --passwordbox "A secret:" 20 60 "First..." 2>&1 >/dev/tty)
$DIALOG --textbox /etc/motd 20 60
AnsCkLst=$($DIALOG --checklist "Check some..." 20 60 12 \
Correct "This demo is useful" off \
Fun "This demo is nice" off \
Strong "This demo is complex" on 2>&1 >/dev/tty)
AnsRadio=$($DIALOG --radiolist "I will:" 20 60 12 \
" -1" "Downgrade this answer" off \
" 0" "Not do anything" on \
" +1" "Upgrade this anser" off 2>&1 >/dev/tty)
out="Your answers:\nLike: $AnsYesNo\nInput: $AnsInput\nSecret: $AnsPass"
$DIALOG --msgbox "$out\nAttribs: $AnsCkLst\nNote: $AnsRadio" 20 60
done
Mehr Proben? Sehen Sie sich Whiptail zur Auswahl von USB-Geräten und USB-Wechselspeichern verwenden an:USBKeyChooser
5. Verwenden des Verlaufs von readline
Beispiel:
#!/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
Dadurch wird eine Datei .myscript.history
erstellt in Ihrem $HOME
Verzeichnis, dann könnten Sie die History-Befehle von readline verwenden, wie Up , Nach unten , Strg +r und andere.
Die einfachste und am weitesten verbreitete Methode, um Benutzereingaben an einem Shell-Prompt zu erhalten, ist read
Befehl. 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.";;
esac
done
Eine andere Methode, auf die Steven Huwig hingewiesen hat, ist Bashs select
Befehl. Hier ist dasselbe Beispiel mit 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
Mit select
Sie müssen die Eingabe nicht bereinigen – sie zeigt die verfügbaren Optionen an, und Sie geben eine Zahl ein, die Ihrer Auswahl entspricht. Es wird auch automatisch eine Schleife durchlaufen, sodass kein while true
erforderlich ist Schleife, um es erneut zu versuchen, wenn sie ungültige Eingaben machen.
Außerdem demonstrierte Léa Gris in ihrer Antwort einen Weg, die Anfragesprache 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)
yesexpr="$1"; noexpr="$2"; yesword="$3"; noword="$4"
while true; do
read -p "Install (${yesword} / ${noword})? " yn
if [[ "$yn" =~ $yesexpr ]]; then make install; exit; fi
if [[ "$yn" =~ $noexpr ]]; then exit; fi
echo "Answer ${yesword} / ${noword}."
done
Offensichtlich bleiben hier andere Kommunikationsstrings unübersetzt (Installieren, Antworten), die in einer vollständigeren Übersetzung behandelt werden müssten, aber sogar eine Teilübersetzung wäre in vielen Fällen hilfreich.
Sehen Sie sich abschließend die ausgezeichnete Antwort von F. Hauri an.
echo "Please enter some input: "
read input_variable
echo "You entered: $input_variable"