bash - template - putty window title command line
Wie deklarieren und verwenden Sie boolesche Variablen im Shell-Skript? (10)
Wie deklariere und verwende boolesche Variablen im Shell-Skript?
Im Gegensatz zu vielen anderen Programmiersprachen trennt Bash seine Variablen nicht durch "type". [1]
Die Antwort ist ziemlich klar. Es gibt keine boolean variable
in bash. Jedoch :
Mit einer declare-Anweisung können wir die Bewertung auf Variablen beschränken. [2]
#!/bin/bash
declare -ir BOOL=(0 1) #remember BOOL can't be unset till this shell terminate
readonly false=${BOOL[0]}
readonly true=${BOOL[1]}
#same as declare -ir false=0 true=1
((true)) && echo "True"
((false)) && echo "False"
((!true)) && echo "Not True"
((!false)) && echo "Not false"
Mit der Option r
in declare
und readonly
wird explizit angegeben, dass die Variablen schreibgeschützt sind . Hoffe, der Zweck ist klar.
Ich habe versucht, eine boolesche Variable in einem Shell-Skript mit der folgenden Syntax zu deklarieren:
variable=$false
variable=$true
Ist das richtig? Wenn ich diese Variable aktualisieren möchte, würde ich auch die gleiche Syntax verwenden? Schließlich ist die folgende Syntax für die Verwendung boolescher Variablen als Ausdrücke richtig:
if [ $variable ]
if [ !$variable ]
POSIX (Portable Betriebssystemschnittstelle)
Ich vermisse hier den Schlüsselpunkt, nämlich die Portabilität. Deshalb hat mein Header POSIX in sich.
Im Wesentlichen sind alle der BASH Antworten korrekt, mit der Ausnahme, dass sie zu sehr BASH sind.
Im Grunde möchte ich nur weitere Informationen zur Portabilität hinzufügen.
[
und]
Klammern wie in[ "$var" = true ]
sind nicht notwendig, und Sie können sie weglassen und dentest
Befehl direkt verwenden:test "$var" = true && CodeIfTrue || CodeIfFalse
Stellen Sie sich vor, was diese Wörter
true
undfalse
für die Shell bedeuten, testen Sie es selbst:echo $((true))
0
echo $((false))
1
Aber mit Zitaten:
echo $(("true"))
bash: "true": syntax error: operand expected (error token is ""true"") sh (dash): sh: 1: arithmetic expression: expecting primary: ""true""
Das gleiche gilt für:
echo $(("false"))
Die Shell kann sie nur als Zeichenfolge interpretieren. Ich hoffe, Sie bekommen die Idee, wie gut es ist, ein richtiges Keyword ohne Anführungszeichen zu verwenden.
Aber niemand hat es in früheren Antworten gesagt.
Was das bedeutet? Nun, mehrere Dinge.
Sie sollten sich daran gewöhnen, dass die booleschen Schlüsselwörter tatsächlich wie Zahlen behandelt werden, das heißt
true
=0
undfalse
=1
, denken Sie daran, dass alle Werte ungleich Null wiefalse
behandelt werden.Da sie wie Zahlen behandelt werden, sollten Sie sie auch so behandeln, dh wenn Sie Variable definieren, sagen Sie:
var_a=true echo "$var_a"
true
Sie können einen entgegengesetzten Wert davon mit erstellen:
var_a=$((1 - $var_a)) echo "$var_a"
1
Wie Sie selbst sehen können, druckt Shell zum ersten Mal eine
true
Zeichenkette, aber seither funktioniert alles über die Nummer0
bzw.1
.
Schließlich, was Sie mit all diesen Informationen tun sollten
Die erste gute Gewohnheit würde
0
statttrue
zuweisen;1
stattfalse
.Die zweite gute Angewohnheit wäre, zu testen, ob die Variable gleich null ist:
test "$var" -eq 0 && CodeIfTrue || CodeIfFalse
Anstatt einen Booleschen Fehler zu fälschen und eine Falle für zukünftige Leser zu hinterlassen, warum nicht einfach einen besseren Wert als true und false verwenden?
Beispielsweise:
build_state=success
if something-horrible; then
build_state=failed
fi
if [[ "$build_state" == success ]]; then
echo go home, you are done
else
echo your head is on fire, run around in circles
fi
BASH verwechselt das Problem wirklich mit dem Beispiel [
, [[
, ((
, $((
usw.)
Alle behandeln die Coderäume der anderen. Ich denke, das ist hauptsächlich historisch, wo bash
so tun musste, als sei er gelegentlich.
Die meiste Zeit kann ich einfach eine Methode auswählen und dabei bleiben. In diesem Fall neige ich dazu, zu deklarieren (vorzugsweise in einer gemeinsamen Bibliotheksdatei, die ich in mein (n) tatsächliche (n) Skript (en) einschließen kann).
TRUE=1; FALSE=0
Ich kann dann den ((
... ))
arithmetischen Operator verwenden, um so zu testen.
testvar=$FALSE
if [[ -d ${does_directory_exist} ]]
then
testvar=$TRUE;
fi
if (( testvar == TRUE )); then
# do stuff because the directory does exist
fi
Sie müssen diszipliniert sein, Ihre
testvar
muss entweder auf$TRUE
oder$FALSE
sein.In
((
...))
Komparatoren brauchen Sie das vorangehende$
, was es lesbarer macht.Ich kann
((
...))
weil$TRUE=1
und$FALSE=0
, also numerische Werte.Der Nachteil ist, gelegentlich ein
$
:testvar=$TRUE
Das ist nicht so schön.
Es ist keine perfekte Lösung, aber es deckt jeden Fall ab, ich brauche einen solchen Test.
Es scheint hier einige Missverständnisse bezüglich der in true
eingebauten Bash zu geben und insbesondere darüber, wie Bash Ausdrücke in Klammern erweitert und interpretiert.
Der Code in Mikus Antwort hat absolut nichts mit der Bash zu tun, die in true
, noch /bin/true
, oder irgendeinem anderen Geschmack des true
Befehls eingebaut ist. In diesem Fall ist true
nichts anderes als eine einfache Zeichenkette, und es wird niemals ein Aufruf an den true
Befehl / Built-In vorgenommen, weder durch die Variablenzuweisung noch durch die Auswertung des Bedingungsausdrucks.
Der folgende Code ist funktional identisch mit dem Code in der Antwort der Miku:
the_world_is_flat=yeah
if [ "$the_world_is_flat" = yeah ]; then
echo 'Be careful not to fall off!'
fi
Der einzige Unterschied besteht darin, dass die vier verglichenen Zeichen "y", "e", "a" und "h" anstelle von "t", "r", "u" und "e" sind. Das ist es. Es wird kein Versuch unternommen, einen Befehl oder Built-in namens yeah
aufzurufen, noch gibt es (im Beispiel von miku) irgendeine Art von spezieller Behandlung, die stattfindet, wenn bash das Token true
interpretiert. Es ist nur eine Zeichenfolge, und eine völlig willkürliche dabei.
Update (2/19/2014): Nachdem ich dem Link in Mikus Antwort gefolgt bin, sehe ich jetzt, wo etwas von der Verwirrung herkommt. Mikus Antwort verwendet einzelne Klammern, aber das Code-Snippet, auf das er verweist, verwendet keine Klammern. Es ist nur:
the_world_is_flat=true
if $the_world_is_flat; then
echo 'Be careful not to fall off!'
fi
Beide Code-Snippets verhalten sich genauso, aber die Klammern ändern komplett, was unter der Haube passiert.
Hier ist was Bash in jedem Fall tut:
Keine Klammern:
- Erweitern Sie die Variable
$the_world_is_flat
auf die Zeichenfolge"true"
. - Versuchen Sie, die Zeichenfolge
"true"
als Befehl zu analysieren. - Suchen Sie und führen Sie den
true
Befehl aus (entweder ein Built-In oder/bin/true
, abhängig von der Bash-Version). - Vergleichen Sie den Exit-Code des
true
Befehls (der immer 0 ist) mit 0. Erinnern Sie sich daran, dass in den meisten Shells ein Exit-Code von 0 den Erfolg anzeigt und alles andere einen Fehler anzeigt. - Da der Exit-Code 0 (Erfolg) war, führe die
then
Klausel derif
Anweisung aus
Klammern:
- Erweitern Sie die Variable
$the_world_is_flat
auf die Zeichenfolge"true"
. - Analysieren Sie den jetzt vollständig expandierten bedingten Ausdruck in der Form
string1 = string2
. Der Operator=
ist der String-Vergleichsoperator von bash. Damit... - Machen Sie einen String Vergleich auf
"true"
und"true"
. - Ja, die zwei Saiten waren gleich, also ist der Wert der Bedingung wahr.
- Führen Sie die
then
Klausel derif
Anweisung aus.
Der Code ohne Klammern funktioniert, weil der Befehl true
Exit-Code 0 zurückgibt, der den Erfolg anzeigt. Der in Klammern $the_world_is_flat
Code funktioniert, weil der Wert von $the_world_is_flat
identisch mit dem String-Literal true
auf der rechten Seite von =
.
Um den Punkt nach Hause zu bringen, bedenken Sie die folgenden zwei Codeschnipsel:
Dieser Code (wenn er mit Root-Rechten ausgeführt wird) startet Ihren Computer neu:
var=reboot
if $var; then
echo 'Muahahaha! You are going down!'
fi
Dieser Code druckt nur "Nice try". Der Neustartbefehl wird nicht aufgerufen.
var=reboot
if [ $var ]; then
echo 'Nice try.'
fi
Update (14.04.2014) Zur Beantwortung der Frage in den Kommentaren zum Unterschied zwischen =
und ==
: AFAIK gibt es keinen Unterschied. Der ==
Operator ist ein Bash-spezifisches Synonym für =
, und soweit ich gesehen habe, funktionieren sie in allen Kontexten genau gleich. Beachten Sie jedoch, dass ich speziell über die =
und ==
String-Vergleichsoperatoren spreche, die in den Tests [ ]
oder [[ ]]
werden. Ich behaupte nicht, dass =
und ==
überall in der Bash austauschbar sind . Zum Beispiel können Sie offensichtlich keine Variablenzuweisung mit ==
, wie zB var=="foo"
( var=="foo"
technisch können Sie das tun, aber der Wert von var
wird "=foo"
, weil bash keins sieht ==
Operator hier, es wird ein Operator =
(Zuweisung) angezeigt, gefolgt von dem Literalwert ="foo"
, der gerade zu "=foo"
.
Auch wenn =
und ==
austauschbar sind, sollten Sie daran denken, dass die Funktionsweise dieser Tests davon abhängt, ob Sie sie in [ ]
oder [[ ]]
und ob die Operanden in Anführungszeichen stehen. Mehr dazu finden Sie hier: Advanced Bash Scripting Guide: 7.3 Andere Vergleichsoperatoren (scrollen Sie nach unten zur Diskussion von =
und ==
).
Hier ist ein einfaches Beispiel, das für mich funktioniert:
temp1=true
temp2=false
if [ "$temp1" = true ] || [ "$temp2" = true ]
then
echo "Do something."
else
echo "Do something else."
fi
Hier ist eine Verbesserung der ursprünglichen Antwort von Miku, die Dennis Williamson 's Bedenken bezüglich des Falles adressiert, wo die Variable nicht gesetzt ist:
the_world_is_flat=true
if ${the_world_is_flat:-false} ; then
echo "Be careful not to fall off!"
fi
Und um zu testen, ob die Variable false
:
if ! ${the_world_is_flat:-false} ; then
echo "Be careful not to fall off!"
fi
Über andere Fälle mit einem unangenehmen Inhalt in der Variablen ist dies ein Problem mit irgendeiner externen Eingabe, die einem Programm zugeführt wird.
Jede externe Eingabe muss validiert werden, bevor Sie ihr vertrauen. Diese Validierung muss jedoch nur einmal durchgeführt werden, wenn diese Eingabe empfangen wird.
Es muss nicht die Leistung des Programms beeinflussen, indem es bei jeder Verwendung der Variablen wie Dennis Williamson schlägt vor.
Ich fand die vorhandenen Antworten verwirrend.
Persönlich möchte ich nur etwas haben, das wie C. aussieht und funktioniert.
Dieser Ausschnitt funktioniert mehrmals täglich in der Produktion:
snapshotEvents=true
if ($snapshotEvents)
then
# do stuff if true
fi
und um alle glücklich zu machen, testete ich:
snapshotEvents=false
if !($snapshotEvents)
then
# do stuff if false
fi
Was auch gut funktioniert hat.
$snapshotEvents
wertet den Inhalt des Wertes der Variable aus. Du brauchst also das $
.
Sie brauchen die Klammern nicht wirklich, ich finde sie nur hilfreich.
Getestet auf: GNU Bash, Version 4.1.11 (2) -Release
Bash Guide für Anfänger , Machtelt Garrels, v1.11, 2008
Verwenden Sie arithmetische Ausdrücke.
#!/bin/bash
false=0
true=1
((false)) && echo false
((true)) && echo true
((!false)) && echo not false
((!true)) && echo not true
Ausgabe:
wahr
nicht falsch
Vor langer Zeit, als alles, was wir hatten, war sh
, Boolean wurde behandelt, indem man sich auf eine Konvention des test
, wo test
einen falschen Ausgangsstatus zurückgibt, wenn er ohne Argumente ausgeführt wird. Auf diese Weise kann man sich eine Variable vorstellen, die als falsch definiert ist und auf einen beliebigen Wert als wahr gesetzt ist. Heutzutage ist test in bash
und ist allgemein bekannt durch seinen Ein-Zeichen-Alias [
(oder eine ausführbare Datei, die man in Shells ohne Dolmen-Notizen verwenden kann):
FLAG="up or <set>"
if [ "$FLAG" ] ; then
echo 'Is true'
else
echo 'Is false'
fi
# unset FLAG
# also works
FLAG=
if [ "$FLAG" ] ; then
echo 'Continues true'
else
echo 'Turned false'
fi
Wegen Zitationskonventionen bevorzugen Script Writer den Compound-Befehl [[
der test
nachahmt test
aber eine schönere Syntax hat: Variablen mit Leerzeichen müssen nicht zitiert werden, man kann &&
und ||
als logische Operatoren mit seltsamer Priorität, und es gibt keine POSIX-Beschränkungen für die Anzahl der Begriffe.
Um beispielsweise zu bestimmen, ob FLAG gesetzt ist und COUNT eine Zahl größer als 1 ist:
FLAG="u p"
COUNT=3
if [[ $FLAG && $COUNT -gt '1' ]] ; then
echo 'Flag up, count bigger than 1'
else
echo 'Nope'
fi
Dieses Material kann verwirrend sein, wenn Leerzeichen, Nulllängen-Strings und Null-Variablen benötigt werden und auch wenn das Skript mit mehreren Shells arbeiten muss.