it-swarm.com.de

Grundlegendes zu booleschen Operatoren im Bash-Skript

phone_missing=false
echo "missing $phone_missing"

if [ ! $phone_missing ]
then
        echo "Lost phone at $readabletime"
        $phone_missing=true
fi

Ich kann das einfach nicht verstehen. Die Linie

echo "missing $phone_missing"

echos missing false, Ich würde die Aussage erwarten

if [ ! $phone_missing ]

um wahr zu sein und die if -Klausel einzugeben, aber nicht? Was vermisse ich hier?

18
asco

Die Variable $phone_missing ist eine Zeichenfolge, die zufällig false enthält. Und eine nicht leere Zeichenfolge ergibt true. Siehe auch http://www.linuxintro.org/wiki/Babe#empty_strings

17
Thorsten Staerk

Ich benutze oft "wahr" und "falsch", da es sich auch um Befehle handelt, die lediglich Erfolg und Misserfolg zurückgeben. Dann können Sie tun

if "$phone_missing"; then ...
16
glenn jackman

Hier ist eine Möglichkeit, dies zu tun, während die wahren/falschen Werte beibehalten werden.

phone_missing=false
if [ "$phone_missing" != false ]; then
    echo "phone_missing is not 'false' (but may be non-true, too)"
fi
if [ "$phone_missing" == true ]; then
    echo "phone_missing is true."
fi

Die doppelten Anführungszeichen um $phone_missing Schützen vor dem Fall, dass die Variable phone_missing Überhaupt nicht definiert ist. Eine andere gängige Redewendung, um sich dagegen zu wehren, ist [ x$phone_missing != xfalse ], Aber die Zitate erscheinen mir natürlicher.

Der Hinweis befindet sich auf der Hilfeseite bash für test:

  STRING      True if string is not empty.
  ...
  ! EXPR      True if expr is false.

Grundsätzlich ist [ $foo ] Wahr, wenn $foo Nicht leer ist. Nicht wahr oder falsch, nur nicht leer. [ ! $foo ] Ist wahr, wenn $ foo leer oder undefiniert ist.

Sie können Ihren Code jederzeit so ändern, dass phone_missing Auf einen nicht leeren Wert gesetzt wird, der true bedeutet. Wenn phone_missing Nicht gesetzt (oder leer - phone_missing="") Ist, ist es falsch. Andernfalls sollten Sie die String-Testoperatoren (= Und !=) Verwenden.

Das andere kleine Problem ist die Zuordnung. Sie haben es als $phone_missing=true, Während es phone_missing=true Sein sollte (kein Dollarzeichen).

Entschuldigung, wenn dies etwas dicht ist, liegt es daran, dass I bin. Es war ein langer Tag. :) :)

5
Alexios

Verwenden Sie keine Zeichenfolge für Boolesche Werte. Verwenden Sie eine Ganzzahl.

Eingang:

val=1
((val)) && echo "true" || echo "false"
val=0
((val)) && echo "true" || echo "false"

Ausgabe:

true
false

Quelle :

((Ausdruck))

Der Ausdruck wird gemäß den unten unter ARITHMETISCHE BEWERTUNG beschriebenen Regeln bewertet. Wenn der Wert des Ausdrucks nicht Null ist, ist der Rückgabestatus 0; Andernfalls lautet der Rückgabestatus 1. Dies entspricht genau dem Ausdruck "Ausdruck".

4
Cyker

Andere Antworten gaben Ihnen eine Lösung, aber ich werde erklären, was mit dem ursprünglichen Denken falsch war.

Bash-Variablen haben keine Typen, daher gibt es keine booleschen Variablen oder Werte wie true oder false. Grundsätzlich sind alle Bash-Variablen nur Strings.

Wenn Sie eine Variable/Zeichenfolge in bash testen, ohne den Testtyp anzugeben (-n oder -z) wird standardmäßig ein -n (String ungleich Null).

Damit [ "$var" ] ist äquivalent zu [ -n "$var" ]. So lange wie $var enthält mindestens 1 Zeichen, es wurde als wahr ausgewertet.

Da Sie den Ausdruck negiert haben, [ ! "$var" ] ist äquivalent zu [ ! -n "$var" ]. Also wenn $var enthält mindestens 1 Zeichen, dann ist der Ausdruck falsch.

Da false (was nur eine Zeichenfolge ist) 5 Zeichen enthält, ist der Ausdruck falsch. Wenn es egal ist, welche Zeichenfolge Sie setzen phone_missing bis (true, 0, 1) lautet der Ausdruck immer false, da phone_missing ist eine Länge ungleich Null. Der einzige Weg, es zu machen true ist phone_missing="" da das die Länge Null ist.

3
wisbucky

Ich hätte dies als Kommentar getan, um James Ko zu unterstützen, hatte aber nicht den Repräsentanten, um zu kommentieren oder öffentlich abzustimmen.

Das Problem hierbei ist, dass die Klammern [] die Notation für einen Vergleichstest wie Wert oder Zeichenfolgengleichheit sind.

Die Wahrhaftigkeit der Zeichenfolge in Bash für eine leere Zeichenfolge lautet "" (Leere Zeichenfolge) und wird als falsch ausgewertet (Rückgabewert 1), und jede nicht leere Zeichenfolge "false", "true" oder "Bob's your Onkel" wird als "true" (Rückgabewert) ausgewertet 0).

Sie können sich das beweisen mit:

    if [ "foo" ]; then 
      echo true is $?; 
    else 
      echo false is $?; 
    fi

Das obige $? Ist eine spezielle Variable, die den Status zum Beenden der letzten Befehle enthält (0 Erfolg und alle> 0 für Fehlercode) und true is 0 Ausgibt. Sie können "foo" Durch alles ersetzen, was Sie möchten, und das Ergebnis ist das gleiche, außer wenn Sie es durch eine leere Zeichenfolge "" Oder '' Ersetzen. In diesem Fall wird das andere ausgewertet Bedingung und Ausgabe false is 1.

Bei Verwendung der Klammern [] wird die interne Anweisung wie! $ phone_missing wird ausgewertet und gibt dann ein 0 für true oder 1 für false an die if-Steueranweisung zurück. Da die Klammer Zeichenfolgen- und Wertevergleiche auswertet, wird $ phone_missing zuerst auf die nicht leere Zeichenfolge "false" erweitert, die von [] als nicht leere Zeichenfolge (oder true) und dann als! Invertiert das Ergebnis, was dazu führt, dass die if-Anweisung einen falschen Wert (oder Rückgabewert 1) erhält, und überspringt den Bedingungskörper, der die else-Anweisung ausführt, falls vorhanden.

Wie James Ko sagte, wäre die Notation, einfach die Variable, die Ihren 'Booleschen Wert' enthält, an die if-Steueranweisung zu übergeben. Hinweis dass in bash ein boolescher Wert für true und false in Kleinbuchstaben geschrieben werden muss wie in: bool_true = true bool_false = false Jeder andere Fall wird als Zeichenfolge und nicht als boolescher Wert ausgewertet.

Anhand Ihres Beispiels und der Antwort von James Ko wäre es also:

phone_missing=false
echo "missing $phone_missing"

if ! $phone_missing 
then
  echo "Lost phone at $readabletime"
  $phone_missing=true
fi

oder wie ich es aus Gründen der Lesbarkeit bevorzuge (syntaktisch gleich und James Ko's)

phone_missing=false
echo "missing $phone_missing"

if ( ! $phone_missing ); then
  echo "Lost phone at $readabletime"
  $phone_missing=true
fi

Andere Antworten wie von Alexios überprüfen buchstäblich den String-Inhalt. Damit eine der folgenden Aussagen zu false führt:

phone_missing=false
if [ "$phone_missing" != false ]; then
    echo "phone_missing is not 'false' (but may be non-true, too)"
fi
if [ "$phone_missing" == true ]; then
    echo "phone_missing is not 'false' (but may be non-true, too)"
fi
if [ "$phone_missing" == Bobs_your_uncle ]; then
    echo "phone_missing is not 'false' (but may be non-true, too)"
fi
1
DVS