linux - template - shell script exit
Wie fordere ich zur Eingabe von Ja/Nein/Abbrechen in einem Linux-Shell-Skript auf? (17)
Ja / Nein / Abbrechen
Funktion
#!/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
}
Verwendung
case $(@confirm 'Confirm?') in
Y ) echo "Yes" ;;
N ) echo "No" ;;
C ) echo "Cancel" ;;
esac
Bestätigen Sie mit einer sauberen Benutzereingabe
Funktion
#!/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
}
Verwendung
if @confirm 'Confirm?' ; then
echo "Yes"
else
echo "No"
fi
Ich möchte die Eingabe in einem Shell-Skript anhalten und den Benutzer zur Auswahl auffordern. Die Standardfrage "Ja, Nein oder Abbrechen". Wie erreiche ich dies in einer typischen Bash-Eingabeaufforderung?
Mindestens fünf Antworten für eine generische Frage.
Es hängt davon ab
- posix compliant: könnte auf schlechten Systemen mit generischen shell Umgebungen funktionieren
- bash spezifisch: Verwenden von sogenannten Bashismen
und wenn du willst
- einfache "in line" Frage / Antwort (generische Lösungen)
- ziemlich formatierte Schnittstellen wie ncurses oder mehr, die mit libgtk oder libqt grafisch sind ...
- Verwenden Sie leistungsstarke Readline History-Funktionen
1. POSIX generische Lösungen
Sie könnten den read
, gefolgt von if ... then ... else
:
echo -n "Is this a good question (y/n)? "
read answer
# if echo "$answer" | grep -iq "^y" ;then
# (Dank Adam Katz Kommentar : Dieser Test ist tragbarer und vermeiden Sie eine Gabel :)
if [ "$answer" != "${answer#[Yy]}" ] ;then
echo Yes
else
echo No
fi
POSIX, aber Single-Key-Funktion
Wenn Sie jedoch nicht möchten, dass der Benutzer Return drückt , könnten Sie schreiben:
( Bearbeitet: Wie @ JonathanLeffler zu Recht vorschlägt, könnte es besser sein, die Konfiguration von stty zu speichern , als sie einfach zu normal zu machen .)
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
Hinweis: Dies wurde unter sh , bash , ksh , dash und busybox !
Gleich, aber warte explizit auf y oder 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
Verwenden von dedizierten Tools
Es gibt viele Tools, die mit libncurses
, libgtk
, libqt
oder anderen grafischen Bibliotheken erstellt wurden. Zum Beispiel mit 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 whiptail
möglicherweise durch ein anderes ähnliches Werkzeug ersetzen:
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
Dabei steht 20
für die Höhe des Dialogfelds in der Anzahl der Zeilen und 60
für die Breite des Dialogfelds. Diese Werkzeuge haben alle nahezu die gleiche 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
Grundlegende 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 ziehe es vor, den case
zu verwenden case
so dass ich sogar auf yes | ja | si | oui
testen könnte yes | ja | si | oui
yes | ja | si | oui
wenn nötig ...
in Übereinstimmung mit einzelnen Schlüsselmerkmal
Unter bash können wir die Länge der beabsichtigten Eingabe für den Lesebefehl angeben:
read -n 1 -p "Is this a good question (y/n)? " answer
Unter bash akzeptiert der Lesebefehl einen Timeout- 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
Einige Tricks für dedizierte Werkzeuge
Anspruchsvollere Dialogfelder, über einfache yes - no
Zwecke hinaus:
dialog --menu "Is this a good question" 20 60 12 y Yes n No m Maybe
Fortschrittsanzeige:
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
5. Verwendung der Geschichte 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
in Ihrem $HOME
Verzeichnis erstellt, als Sie die readline-History-Befehle wie Up , Down , Ctrl + r und andere verwenden könnten.
Als Freund eines Ein-Zeilen-Befehls habe ich folgendes benutzt:
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=;
Schriftliche Longform, das funktioniert so:
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=;
Bash hat zu diesem Zweck ausgewählt.
select result in Yes No Cancel
do
echo $result
done
Diese Lösung liest ein einzelnes Zeichen und ruft eine Funktion auf eine Ja-Antwort auf.
read -p "Are you sure? (y/n) " -n 1
echo
if [[ $REPLY =~ ^[Yy]$ ]]; then
do_something
fi
Ein einfacher Weg dies zu tun ist mit xargs -p
oder parallel --interactive
.
Ich mag das Verhalten von xargs ein wenig besser dafür, weil es jeden Befehl direkt nach der Eingabeaufforderung wie andere interaktive unix-Befehle ausführt, anstatt die yesses zu sammeln, um am Ende zu laufen. (Sie können Strg-C drücken, nachdem Sie die gewünschten Ergebnisse erreicht haben.)
z.B,
echo *.xml | xargs -p -n 1 -J {} mv {} backup/
Hier ist etwas, was ich zusammengestellt habe:
#!/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
Ich bin ein Anfänger, also nimm das mit einem Körnchen Salz, aber es scheint zu funktionieren.
Ich habe die case
Anweisung in einem solchen Szenario ein paar Mal verwendet, die Verwendung der Case-Anweisung ist ein guter Weg, um darüber zu gehen. Eine while
Schleife, die den Fallblock kapselt, die eine boolesche Bedingung verwendet, kann implementiert werden, um noch mehr Kontrolle über das Programm zu behalten und viele andere Anforderungen zu erfüllen. Nachdem alle Bedingungen erfüllt sind, kann eine break
verwendet werden, die die Kontrolle an den Hauptteil des Programms zurückgibt. Um andere Bedingungen zu erfüllen, können natürlich bedingte Anweisungen hinzugefügt werden, um die Kontrollstrukturen zu begleiten: case
Anweisung und mögliche while
Schleife.
Beispiel für die Verwendung einer Fallanweisung 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
Inspiriert von den Antworten von @Mark und @Myrddin habe ich diese Funktion für eine universelle Eingabe erstellt
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
}
benutze es so:
unipromtp "Select an option: (a)-Do one (x)->Do two (f)->Do three : " "a x f" selection
echo "$selection"
Mir ist aufgefallen, dass niemand eine Antwort gepostet hat, die ein mehrzeiliges Echo-Menü für solch einfache Benutzereingaben zeigt. Hier ist mein Beispiel:
#!/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
Diese Methode wurde in der Hoffnung veröffentlicht, dass jemand sie nützlich und zeitsparend finden könnte.
Sie können den integrierten Lesebefehl verwenden. Verwenden Sie die Option -p
, um den Benutzer mit einer Frage zu fragen.
Seit BASH4 können Sie nun -i
, um eine Antwort vorzuschlagen, so dass der Benutzer nur return
drücken muss, um ihn einzugeben:
read -e -p "Enter the path to the file: " -i "/usr/local/etc/" FILEPATH
echo $FILEPATH
(Aber denken Sie daran, die "readline" -Option zu verwenden, um die Zeilenbearbeitung mit den Pfeiltasten zu ermöglichen)
Um ein nettes ncurses-ähnliches Eingabefeld zu erhalten, benutzen Sie den Befehlsdialog wie folgt:
#!/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
Das Dialogpaket wird standardmäßig mindestens mit SUSE Linux installiert.
generischer wäre:
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
}
Die einfachste und am weitesten verbreitete Methode, Benutzereingaben an einer Shell-Eingabeaufforderung zu erhalten, ist der read
. Der beste Weg, 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 das selbe 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
Bei select
Sie die Eingabe nicht bereinigen - sie zeigt die verfügbaren Auswahlmöglichkeiten an und Sie geben eine Nummer ein, die Ihrer Auswahl entspricht. Es wird auch automatisch eine Schleife durchlaufen, so dass es nicht nötig ist, eine while true
Schleife zu wiederholen, wenn sie eine ungültige Eingabe liefert.
Schauen Sie sich auch die ausgezeichnete Antwort von F. Hauri an.
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?"
...
read -e -p "Enter your choice: " choice
Mit der Option -e
kann der Benutzer die Eingabe mit den Pfeiltasten bearbeiten.
Wenn Sie einen Vorschlag als Eingabe verwenden möchten:
read -e -i "yes" -p "Enter your choice: " choice
-i
Option druckt eine suggestive Eingabe.
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!'