while

J

Jo8558

Grünschnabel
Ich hoffe jetzt mal das die Frage noch nicht gestellt wurde!

Wieso funzt das nicht? Es ist eine einfache ja nein frage, bei der verhindert werden soll das man was anderes als Y oder N eingibt:

echo "Enter your answer (Y or N)"
read answer
while [ $answer = "" ] && [ $answer != Y ] && [ $answer != y ] && [ $answer != N ] && [ $answer != n ]
do
echo "Enter your answer (Y or N)"
read answer
done
...

es funktioniert wenn man den ersten teil des while weglässt aber ich will ja verhindern das der user einfach auf Enter drückt

lg
Jo
 
Code:
while [  $answer = "" ] && ...
Wenn ich irgendwas ausser Y|y|n|N eingeben, z.B. 'Nein', dann ist diese Bedingung schon falsch, so dass die Schleife unterbrochen wird.
Lass das
Code:
[  $answer = "" ] &&
mal weg!
 
richtig, ich will das man nur Y|y|n|N eingeben kann, wenn ich das [ $answer = "" ] weglasse funktioniert das man nur Y|y|n|N eingeben kann aber dann bekomme ich eine fehlermeldung wenn ich einfach enter drücke und er spring nicht in die while loop
 
Wie wäre es mit sowas?
Code:
# Ask a question and return 0 on 'yes' or 1 on 'no'
ask() {

	USAGE="\
	Usage: ask [The yes / no question]\nReturns 0 on \"y\" or 1 on \"n\"."

	if [ $# -lt 1 ]; then
		echo -e $USAGE
		return 2
	fi

	echo -n "$@ [y/n]: " 
	read ANSWER
	shopt -s nocasematch
	case "$ANSWER" in
		j|y|ja|yes)
			return 0;;
		n|no|nein)
			return 1;;
		*)	
			ask "Please enter 'yes' or 'no'"
			return $?;;
	esac
}
 
is das nicht ein wenig gar aufwendig nur damit ich verhindern kann das der user einfach auf enter drückt? ;) oder gibt es keine andere möglichkeit?

lg
 
Ich sehe da jetzt keinen großen Aufwand in der Funktion. Du kannst ja gerne auch die Hilfeausgabe weglassen:
Code:
ask() {
	echo -n "$@ [y/n]: " 
	read ANSWER
	shopt -s nocasematch
	case "$ANSWER" in
		j|y|ja|yes)
			return 0;;
		n|no|nein)
			return 1;;
		*)	
			ask "Please enter 'yes' or 'no'"
			return $?;;
	esac
}

PS: Falls es dir nur darum geht, dass nicht einfach "Enter" gedrückt wird, ohne das Ergebnis abzufragen, kannst du den Benutzer mit
Code:
ANSWER=""; while [ -z "$ANSWER" ]; do read ANSWER; done
beliebig lang nerven. :D
 
Stimmt - wobei ich den Effekt auch mit der leeren Abfrage bekomme, bzw. eine Fehlermeldung bzgl. 'while'. 'if' scheint damit weniger Probleme zu haben, das folgende Skript funktioniert beim ersten Test:
Code:
read -p "Enter your answer (Y or N)" answer
if [ -z $answer ]; then answer="weiterfragen"; fi

while [ $answer != Y ] && [ $answer != y ] && [ $answer != N ] && [ $answer != n ] 
do
        read -p "Enter your answer (Y or N)" answer
        if [ -z $answer ]; then answer="weiterfragen"; continue; fi
done
 
Ich glaube, ich verstehe nun, was du haben möchtest.
Du solltest den auszuwertenden Ausdruck komplett an while übergeben:
Code:
ANSWER=""; while [ "$ANSWER" != "y" -a "$ANSWER" != "Y" -a "$ANSWER" != "n" -a "$ANSWER" != "N" ]; do read -p "Enter your answer (Y or N)" ANSWER; done
 
Weswegen funktioniert dieses Skript:
Code:
ANSWER="";
while [ -z $ANSWER ] || [ $ANSWER != Y ] && [ "$ANSWER" != 'N' ]; do
        read -p "Eingabe: " ANSWER;
done
dieses auch:
Code:
answer="";
while [ -z $answer ] || [ "$answer" != 'Y' ] && [ "$answer" != 'y' ] && [ "$answer" != 'N' ] && [ "$answer" != 'n' ]
do
read -p "Enter your answer (Y or N)" answer;
done
aber nur, wenn man ausser in der 'Y'-Abfrage, die '$answer' in Anfuehrungszeichen setzt? In der (ersten nach ||) Abfrage nach 'Y' kann man sie weglassen. Weswegen ist das so?
 
Wenn im ersten Durchlauf
Code:
$answer
ausgewertet wird, ist es der leere String.
Also steht für die bash da
Code:
test "" != 'Y'
, was wahr ist.
Würdest du die Anführungszeichen weglassen (bitte, bitte, nie bei Strings machen!), stünde für die bash da
Code:
test != 'Y'
, was keinen Sinn ergibt!
 
Google einfach mal "bash stringvergleich" (oder einem entsprechenden Ausdruck in Englisch) - oder schau in den üblichen Bash-Tutorials nach.

Syntax ist halt Syntax.
 
@Schard/ @marce:
Das ist mir schon klar. Meine Frage war, weswegen dieses Skript:
Code:
while [ -z $ANSWER ] || [ $ANSWER != Y ] && [ "$ANSWER" != 'N' ]; do
        read -p "Eingabe: " ANSWER;
done
echo "Antwort: $ANSWER"
funktioniert, waehrend dieses Skript
Code:
while [ -z $ANSWER ] || [ $ANSWER != Y ] && [ $ANSWER != 'N' ]; do
        read -p "Eingabe: " ANSWER;
done
echo "Antwort: $ANSWER"
beim Aufruf den Fehler
Code:
while.sh: line 1: [: !=: unary operator expected
ergibt. Beim ersten logischen Ausdruck der '&&'-Kette scheinen keine Anfuehrungszeichen vonnoeten zu sein, nur bei den restlichen.
 
@tgruene: Und genau das habe ich in Post #10 beschrieben. :D
Der erste Teil der logischen Kette hat nur einen unären Operator, und das Resultat ist wahr.
Code:
test -z $ANSWER
expandiert zu
Code:
test -z
Da das wahr ist, wird der Block nach dem
Code:
||
gar nicht ausgeführt, sondern es wird zum Block nach dem
Code:
&&
gesprungen.
Und dieser funktioniert wie in #10 beschrieben nicht:
Code:
test != 'Y'
bash: test: !=: Einstelliger (unärer) Operator erwartet.

MfG

Schard
 
Hallo Schard,
ich war davon ausgegangen, dass && staerker bindet als ||, d.h., dass
Code:
 A || B && C
auch in der bash aequivalent ist zu
Code:
 A || ( B && C)
so wie hier ganz unten beschrieben. Vielleicht wertet bash bei (A&&B) zuerst B aus. Eigentlich ist die Diskussion muessig, da es ja eigentlich guter Programmierstil ist, Anfuehrungszeichen und Klammer zu setzen.
 
@tgruene:
Nein, nein, nein. :)
Die Operatoren
Code:
||
und
Code:
&&
werten zuvorige Rückgabewerte von Programmen und Funktionen aus und führen dann entsprechend das folgende Statement aus.
Code:
A || B
heißt, dass B genau dann ausgeführt wird, wenn der Rückgabewert von A sich von 0 unterscheidet (nicht Null ist).
Code:
A && B
heißt, dass B genau dann ausgeführt wird, wenn der Rückgabewert von A gleich 0 ist.
Dein Beispiel
Code:
 A || B && C
bedeutet, dass B genau dann ausgeführt wird, wenn der Rückgabewert von A sich von 0 unterscheidet. Und C wird genau dann ausgeführt, wenn der Rückgabewert von A oder B gleich 0 ist.

MfG

Schard
 
Dann ist die bash wohl ein kleiner Revoluzzer, gegen bestehende Regeln der Wertigkeit von Operatoren aufzubegehren. So wie es hier auf Wikipedia steht, habe ich es zumindest mehrfach gelernt, im uebertragenen Sinne ziemlich frueh in der Schule, wo
Code:
3+4*5 = 3+(4*5)=23
und eben nicht
Code:
35 = (3+4)*5 != 3+4*5
Analog (weil '&&' staerker bindet als '||', ebenso wie '*' staerker bindet als '+') ist
Code:
A||B&&C = A || ( B && C) != (A || B) && C
.

Letzteres ist die Variante, die Du beschrieben hast. Allerdings laesst sich das Raetsel loesen, wenn ( B && C) von der bash von rechts nach links geprueft wird, und nicht in Leserichtung. Dagegen laesst sich ja auch nichts einwenden.

Moeglicherweise ist das in der bash als Rekursion implementiert, dann koennte es zu dem beschriebenen Phaenomen ja kommen.
 

Ähnliche Themen

script sshpass

Shell Skript beschleunigen

Telefoninterview (Wie sich auf Bash-Shell-Fragen vorbereiten?)

Sed: Bestimmtes Feld einer "Zeile mit mehreren Feldern" ergänzen

Neuling braucht Hilfe bei Shellprogrammierung

Zurück
Oben