Wie erstelle ich eine bedingte Zuweisung in Bash?

70

Ich suche nach einer Möglichkeit, bedingte Zuweisungen in Bash zu erstellen:

In Java sieht es so aus:

int variable= (condition) ? 1 : 0;
Neuquino
quelle

Antworten:

69

Gemäß Jonathans Kommentar:

variable=$(( 1 == 1 ? 1 : 0 ))  

BEARBEITEN:

Ich habe die ursprüngliche Antwort überarbeitet, die nur echoden Wert des Bedingungsoperators hatte und tatsächlich keine Zuordnung zeigte.

Anthony Forloney
quelle
1
Nit-Pick: Das ist keine Aufgabe - es ist nur ein bedingter Ausdruck. Funktioniert jedoch, variable=$(( 1 == 1 ? 1 : 0 ))solange um das erste '=' - Zeichen keine Leerzeichen vorhanden sind. Sie können danach alle Leerzeichen weglassen und es funktioniert auch - aber denken Sie an die Lesbarkeit.
Jonathan Leffler
3
Sie können vollständige Abstandsfreiheit haben (und das Dollarzeichen fallen lassen), wenn Sie die öffnenden Doppelklammern ganz nach links verschieben. (( variable = 1 == 1 ? 1 : 0 ))oder (( variable = (1 == 1) ? 1 : 0 ))Aber es könnte argumentiert werden, dass es besser lesbar ist, wie in der Antwort angegeben.
Dennis Williamson
42
Es sollte auch beachtet werden, dass dieser Operator nur für arithmetische Operationen in Bash funktioniert.
Dennis Williamson
13
Was ist, wenn die Variable, die ich festlegen möchte, eine Zeichenfolge ist?
Giovanni Botta
25
Dies funktioniert nicht für Strings: echo $ ((1 == 1? 'Hallo': 'Welt'))
4aRk Kn1gh7
74

Wenn Sie eine Möglichkeit zum Definieren von Standardeinstellungen in einem Shell-Skript wünschen, verwenden Sie folgenden Code:

: ${VAR:="default"}

Ja, die Zeile beginnt mit ':'. Ich verwende dies in Shell-Skripten, damit ich Variablen in ENV überschreiben oder die Standardeinstellung verwenden kann.

Dies hängt damit zusammen, dass dies mein häufigster Anwendungsfall für diese Art von Logik ist. ;]

Demosthenex
quelle
3
Dies ist eine wertvolle Technik, aber die einzige Bedingung, die mit der Notation ': =' unterstützt wird, ist 'auf "Standard" gesetzt, wenn der Wert nicht gesetzt oder leer ist'. Die allgemeinere Notation in der Frage wird direkt in bash unterstützt.
Jonathan Leffler
2
Ich stimme vollkommen zu, ich habe ihm einen Haftungsausschluss gegeben, weil er etwas vom Thema abweicht.
Demosthenex
3
Lassen Sie den Doppelpunkt vor gleichen Tests weg, damit die Variable nicht gesetzt wird, und ändern Sie ihn nicht, wenn er null ist.
Dennis Williamson
Verwandte nützliche Erklärung mit einem Doppelpunkt und der Parameter Expansion beginnt diese Antwort .
GcL
33
myvar="default" && [[ <some_condition_is_true> ]]  && myvar="non-default"

echte Beispiele:

DELIM="" && [[ "$APP_ENV_RESOLVED" != "" ]] && DELIM=$INNER_DELIM

Die Bedingung kann auch "((...))" sein:

filepath=/proc/drbd && (( $# > 0 )) && filepath=$1
Kevin Little
quelle
27

Zusätzlich zu den anderen allgemeineren Antworten (insbesondere gemäß Jonathans Kommentar und Kevins allgemeinerer Antwort [die auch Zeichenfolgen unterstützt]) möchte ich die folgenden zwei Lösungen hinzufügen:


Setzen der Variablen auf entweder 0oder 1basierend auf der Bedingung:

(Wie das Beispiel der Frage zeigt.)

Die allgemeine Form würde lauten

(condition); variable=$?;

Dabei $variableergibt sich entweder 0oder 1und conditionkann ein beliebiger gültiger bedingter Ausdruck sein .

ZB eine Variable prüfen ...

[[ $variableToCheck == "$othervariable, string or number to match" ]]
variable=$?

... oder die Existenz einer Datei überprüfen ...

[ -f "$filepath" ]
fileExists=$?

... oder überprüfen Sie den Zahlenwert von $myNumber:

(( myNumber >= 1000000000 ))
is_huge_number=$?


Die Vorteile dieser Lösung sind die folgenden

  • Es unterstützt beliebige bedingte Ausdrücke , einschließlich Zeichenfolgen
    (die in arithmetischen Ausdrücken von Jonathans Lösung nicht unterstützt werden ).
  • das variablewird auf jeden Fall deklariert , anders als in Griffons Antwort :
    [ -z "$variable" ] && variable="defaultValue"
    Was wichtig wäre, wenn Sie es später benennen möchten (z. B. innerhalb einer Funktion).


Bitte beachten Sie: In Bash $?enthält die spezielle Variable immer den Exit-Code der zuvor ausgeführten Anweisung (oder des Anweisungsblocks; weitere Informationen finden Sie in der Man-Bash ). Als solches wird ein positives Ergebnis im Allgemeinen durch den Wert dargestellt0 , nicht 1(siehe meinen Kommentar unten , danke Assimilater für den Hinweis ). Wenn also die Bedingung wahr ist (zB [[2 eq 2]]), dann $?=0.

Wenn Sie stattdessen 0 oder 1 in Ihrer Variablen benötigen (z. B. um zu drucken oder mathematische Berechnungen durchzuführen), müssen Sie eine boolesche Negation mit einem führenden Ausrufezeichen verwenden (wie von GypsySpellweaver in den Kommentaren unten hervorgehoben): ( ! condition ); variable=$?oder ! ( condition ); variable=$?. (Die Lesbarkeit in Bezug auf das, was passiert, ist jedoch möglicherweise weniger offensichtlich.)

Eine andere mögliche Lösung von Jonathan wäre variable=$(( 1 == 1 ? 1 : 0 ))- was jedoch darin besteht, eine Unterschale zu erstellen.

Wenn Sie die Erstellung eines Subshels vermeiden, eine gute Lesbarkeit gewährleisten oder beliebige Bedingungen haben möchten, verwenden Sie eine der folgenden Lösungen.


Setzen der Variablen auf beliebige Werte:

Wie in den meisten anderen Antworten wird es wie folgt angepasst:

(condition) \
    && variable=true \
    || variable=false

zB wie in

[[ $variableToCheck == "$othervariable, string or number to match" ]] \
    && variable="$valueIfTrue" \
    || variable="$valueIfFalse"

oder um 1 in einer positiven Prüfung und 0 bei einem Fehler zu erhalten (wie im Beispiel der Frage):

[[ $variableToCheck == "$othervariable, string or number to match" ]] \
    && variable=1 \
    || variable=0

(Für das letzte Beispiel kann - wie bereits in den obigen Anmerkungen erwähnt - dasselbe mit einer booleschen Negation unter Verwendung eines führenden Ausrufezeichens erreicht werden:

[[ ! $variableToCheck == "$othervariable, string or number to match" ]]
variable=$?


Die Vorteile dieser Lösung sind die folgenden

  • es könnte als etwas besser lesbar angesehen werden als Kevins Antwort
    myvar="default" && [[ <some_condition_is_true> ]] && myvar="non-default" , und
  • das $valueIfTruebedingt ausgewertet nur , wenn nötig ,
    was für den Fall, dass Sie etwas tun würden, von Bedeutung ist
    • mit Nebenwirkung, wie
      • variable=$((i++)), oder
      • { variable=$1; shift; }
    • hohe Berechnung, wie
      • variable=$(find / -type f -name ListOfFilesWithThisNameOnMySystem)
  • ist etwas kürzer als die Antwort von ghostdog74
    (was jedoch großartig ist, wenn Sie mehrere Bedingungen haben!)
  • öffnet keine Unterschale wie in der Antwort von Pierre
  • und wie oben:
    • Es unterstützt beliebige bedingte Ausdrücke , einschließlich Zeichenfolgen
      (die in arithmetischen Ausdrücken von Jonathans Lösung nicht unterstützt werden ).
    • das variablewird auf jeden Fall deklariert , anders als in Griffons Antwort :
      [ -z "$variable" ] && variable="defaultValue"
      Was wichtig wäre, wenn Sie es später benennen möchten (z. B. innerhalb einer Funktion).
Martin Rüegg
quelle
Das Ergebnis Ihrer ersten Lösung ist für mich etwas verwirrend. Eine Bedingung, die als wahr ausgewertet wird, ergibt einen Wert von 0; wo eine Bedingung, die zu falsch ausgewertet wird, zu einem Wert von 1 führt
Assimilater
Vielleicht habe ich es aber falsch gemacht. Ich teste mit[ "$1" == "--all" ] ; allperiods=$? ; echo $allperiods
Assimilater
1
@Assimilater, ich stimme zu, dass 0 und 1 verwirrend sein könnten. Dies ergibt sich aus der Tatsache, dass ein Exit-Code eines Programms oder einer Anweisung normalerweise 0 ist, wenn alles in Ordnung ist, und ein beliebiger Code (normalerweise zwischen 1 und 254) für Fehler. Daher executable && executesWhenOk || executesWhenNotOkund in unserem Szenario ist der Test die "ausführbare Datei" (oder Anweisung, um genau zu sein), und die spezielle Variable $?enthält den Ergebniscode der letzten Anweisung. hoffe das hilft zu klären.
Martin Rüegg
Das hilft :) (Sie könnten erwägen, es der Antwort hinzuzufügen;))
Assimilater
1
Die "normale" Boolesche Logik, an die Programmierer angepasst sind, 1ist trueund 0ist false, kann in diesem Fall mit dem NOT leicht erreicht werden ! , indem Operator auf den Ausdruck angewendet wird. Entweder innerhalb oder außerhalb des 'Ausdrucks'. ( ! condition ); variable=$?oder ! ( condition ); variable=$?Eine solche, [ ! -f "$filepath" ]; fileExists=$?die als Programmierer funktioniert, ist gewohnt: 1 Datei existiert und 0 Datei fehlt.
Chindraba
15

Ich wollte eine bedingte Aufgabe mit Strings machen und endete mit:

SOWHAT=$([ "$MYVALUE" = "value" ] && echo "YES" || echo "NO")
Pierre Maoui
quelle
8

Ein großes Dankeschön an @Demosthenex und insbesondere an @Dennis Williamson für die kürzeste und einfachste Lösung, die ich je gesehen habe. Überlassen Sie es dem Bash , um eine Reihe von Klammern für eine einfache ternäre Zuordnung zu benötigen . Ahh, die 60er ! Und um alles in einem Beispiel zusammenzufassen ...

echo $BASHRULES;             # not defined
                             # no output
: ${BASHRULES:="SCHOOL"}     # assign the variable
echo $BASHRULES              # check it
SCHOOL                       # correct answer
: ${BASHRULES="FOREVER?"}    # notice the slightly different syntax for the conditional assignment
echo $BASHRULES              # let's see what happened!
SCHOOL                       # unchanged! (it was already defined)

Ich habe das vor langer Zeit geschrieben. In diesen Tagen würde ich mich wahrscheinlich mehr über eine Lösung wie ... freuen.

PLATFORM=iphonesimulator
OTHERSDK=iphone && [[ $PLATFORM=~os ]]      \
                &&     OTHERSDK+=simulator  \
                ||     OTHERSDK+=os

$OTHERSDKiphoneos

Alex Gray
quelle
2
Vielen Dank, Herr @alex grau. Dies ist ein ausgezeichneter syntaktischer Pfeil, den jeder in seinem bashKöcher haben sollte. Für Neugierige und / oder Unglückliche, die ihn hier entdecken, spielt diese Art der bedingten Zuweisung auch gut mit exportAussagen - die Sie zwischen das Doppelpunktpräfix und den Dollar setzen. Zeichen Aussage-y Teil, zB: export ${YO_DOGG:="global environment default"}
fish2000
1
Ihre zweite Lösung stellt tatsächlich die zweite Lösung meiner Antwort dar und wurde erst hinzugefügt, nachdem ich sie veröffentlicht habe. Eine kurze Referenz wäre schön gewesen. Bitte beachten Sie auch, iphonesimulatordass die osobige Lösung enden würde , da sie die Zeichenfolge nicht enthält OTHERSDK=iphonesimulator.
Martin Rüegg
Ich mag diese kurze Antwort. Einige der anderen waren zu lang.
MarkHu
5

Wenn Sie einen Wert zuweisen möchten, sofern die Variable nicht leer ist, verwenden Sie Folgendes:

[ -z "$variable" ] && variable="defaultValue"

Sie können sich auch gegenseitig auf die Bedingung stellen []

Gänsegeier
quelle
3
Die variable Erweiterung soll dies wie folgt behandeln: ${variable:='defaultValue'}
Stphane
3

ein anderer Weg

case "$variable" in
  condition ) result=1;;
  *) result=0;;
esac
Ghostdog74
quelle