Ich habe diese Woche Bash gelernt und bin auf einen Haken gestoßen.
#!/bin/sh
if [ false ]; then
echo "True"
else
echo "False"
fi
Dies gibt immer True aus, obwohl die Bedingung etwas anderes anzuzeigen scheint. Wenn ich die Klammern entferne []
, funktioniert es, aber ich verstehe nicht warum.
bash
conditional-operator
zehn Meilen
quelle
quelle
#!/bin/sh
kein Bash-Skript, sondern ein POSIX-sh-Skript. Selbst wenn der POSIX sh-Interpreter auf Ihrem System von bash bereitgestellt wird, werden einige Erweiterungen deaktiviert. Wenn Sie Bash-Skripte schreiben möchten, verwenden Sie#!/bin/bash
oder das lokal geeignete Äquivalent (#!/usr/bin/env bash
um den ersten Bash-Interpreter im PATH zu verwenden).[[ false ]]
auch.Antworten:
Sie führen den Befehl
[
(akatest
) mit dem Argument "false" aus und nicht den Befehlfalse
. Da "false" eine nicht leere Zeichenfolge ist, ist dertest
Befehl immer erfolgreich. Löschen Sie den Befehl, um den[
Befehl tatsächlich auszuführen .quelle
bash
hat keinen booleschen Datentyp und daher keine Schlüsselwörter, die wahr und falsch darstellen. Dieif
Anweisung prüft lediglich, ob der von Ihnen erteilte Befehl erfolgreich ist oder fehlschlägt. Dertest
Befehl nimmt einen Ausdruck an und ist erfolgreich, wenn der Ausdruck wahr ist. Eine nicht leere Zeichenfolge ist ein Ausdruck, der wie in den meisten anderen Programmiersprachen als wahr ausgewertet wird.false
ist ein Befehl, der immer fehlschlägt. (Analogtrue
ist ein Befehl, der immer erfolgreich ist.)if [[ false ]];
gibt auch true zurück. Wie auchif [[ 0 ]];
. Undif [[ /usr/bin/false ]];
überspringt den Block auch nicht. Wie kann false oder 0 als ungleich Null bewertet werden? Verdammt, das ist frustrierend. Wenn es darauf ankommt, OS X 10.8; Bash 3.false
eine boolesche Konstante oder0
ein ganzzahliges Literal. beide sind nur gewöhnliche Saiten.[[ x ]]
entspricht[[ -n x ]]
einer Zeichenfolgex
, die nicht mit einem Bindestrich beginnt.bash
hat nicht alle Booleschen Konstanten in jedem Kontext. Zeichenfolgen, die wie Ganzzahlen aussehen, werden innerhalb(( ... ))
oder mit Operatoren wie-eq
oder-lt
innerhalb als solche behandelt[[ ... ]]
.if $predicate
kann dies leicht missbraucht werden, um feindlichen Code auf eine Weise auszuführen,if [[ $predicate ]]
die dies nicht kann.Eine schnelle boolesche Grundierung für Bash
Die
if
Anweisung nimmt einen Befehl als Argument (wie auch&&
,||
etc.). Der ganzzahlige Ergebniscode des Befehls wird als Boolescher Wert interpretiert (0 / null = true, 1 / else = false).Die
test
Anweisung verwendet Operatoren und Operanden als Argumente und gibt einen Ergebniscode im gleichen Format wie zurückif
. Ein Alias dertest
Anweisung ist[
, mit dem häufigif
komplexere Vergleiche durchgeführt werden.Die Anweisungen
true
undfalse
tun nichts und geben einen Ergebniscode zurück (0 bzw. 1). So können sie in Bash als boolesche Literale verwendet werden. Wenn Sie die Anweisungen jedoch an einer Stelle platzieren, an der sie als Zeichenfolgen interpretiert werden, treten Probleme auf. In deinem Fall:So:
Dies ist vergleichbar mit so etwas wie tun
echo '$foo'
vs.echo "$foo"
.Bei Verwendung der
test
Anweisung hängt das Ergebnis von den verwendeten Operatoren ab.Kurz gesagt , wenn Sie nur als Pass - Test etwas wollen / nicht bestanden (auch bekannt als „true“ / „false“), übergeben Sie dann einen Befehl an Ihrer
if
oder&&
usw. Anweisung, ohne Klammern. Verwenden Sie für komplexe Vergleiche Klammern mit den richtigen Operatoren.Und ja, ich bin mir bewusst, dass es in Bash keinen nativen booleschen Typ gibt, und das
if
und[
undtrue
sind technisch "Befehle" und keine "Anweisungen"; Dies ist nur eine sehr grundlegende, funktionale Erklärung.quelle
if (( $x )); then echo "Hello"; fi
wird die Meldung für,x=1
aber nicht fürx=0
oderx=
(undefiniert) angezeigt.Ich habe festgestellt, dass ich eine grundlegende Logik ausführen kann, indem ich Folgendes ausführe:
quelle
( $A && $B )
ist eine überraschend ineffiziente Operation - Sie erzeugen einen Unterprozess durch Aufrufenfork()
, teilen dann den Inhalt von$A
auf, um eine Liste von Elementen (in diesem Fall der Größe eins) zu generieren, und bewerten jedes Element als Glob (in diesem Fall eines) das ergibt sich selbst) und führt dann das Ergebnis als Befehl aus (in diesem Fall als eingebauter Befehl).true
undfalse
Zeichenfolgen von einem anderen Ort stammen, besteht außerdem das Risiko, dass sie tatsächlich andere Inhalte alstrue
oder enthaltenfalse
, und Sie können unerwartetes Verhalten bis hin zur Ausführung beliebiger Befehle erhalten.A=1; B=1
undif (( A && B ))
- sie als numerisch zu behandeln - oder[[ $A && $B ]]
eine leere Zeichenfolge als falsch und eine nicht leere Zeichenfolge als wahr zu behandeln.Durch die Verwendung von true / false wird die Unordnung in Klammern beseitigt ...
quelle
[[ "$0" =~ "bash" ]]
dass das Skript für mich funktioniert.