2010-09-29 8 views
194

Ich möchte mehrere Bedingungen wie folgt darstellen:Wie werden mehrere Bedingungen in einer Shell-If-Anweisung dargestellt?

if [ ($g -eq 1 -a "$c" = "123") -o ($g -eq 2 -a "$c" = "456") ] 
then 
    echo abc; 
else 
    echo efg; 
fi 

aber wenn ich das Skript ausführen, zeigt es

syntax error at line 15: `[' unexpected, 

wo Linie 15 ist derjenige zeigt, wenn ....

Was ist falsch an dieser Bedingung? Ich denke, etwas stimmt nicht mit dem ().

+4

Sie fragt nicht über Shell-Bedingungen, aber [Test] (https://de.wikipedia.org/wiki/Test_%28Unix % 29) Bedingungen. Der gesamte Ausdruck in Ihrem Beispiel wird durch 'test' (' ['') und nicht durch die Shell ausgewertet. Die Shell wertet nur den Exit-Status von '[' aus. – ceving

+0

Siehe auch http://stackoverflow.com/questions/16203088/multiple-conditions-if-statement-bash-script – tripleee

Antwort

252

Klassische Technik (Escape Metazeichen):

if [ \("$g" -eq 1 -a "$c" = "123" \) -o \("$g" -eq 2 -a "$c" = "456" \) ] 
then echo abc 
else echo efg 
fi 

ich die Verweise auf $g in doppelte Anführungszeichen eingeschlossen haben; Das ist im Allgemeinen eine gute Übung. Streng genommen werden die Klammern nicht benötigt, weil die Priorität -a und -o sie auch ohne sie korrekt macht.

Beachten Sie, dass die -a und -o Betreiber Teil der POSIX-Spezifikation für test sind, auch bekannt als [, vor allem für die Abwärtskompatibilität (da sie zum Beispiel ein Teil der test in 7. Auflage UNIX waren), aber sie sind explizit gekennzeichnet als "veraltet" von POSIX. Bash (siehe conditional expressions) scheint die klassischen und POSIX-Bedeutungen für -a und -o mit seinen eigenen alternativen Operatoren, die Argumente entgegennehmen, vorwegzunehmen.


Mit etwas Sorgfalt, können Sie den modernere [[ Operator verwenden, aber darüber im Klaren sein, dass die Versionen in Bash und Korn Shell (zum Beispiel) nicht identisch sein müssen.

for g in 1 2 3 
do 
    for c in 123 456 789 
    do 
     if [[ ("$g" -eq 1 && "$c" = "123") || ("$g" -eq 2 && "$c" = "456") ]] 
     then echo "g = $g; c = $c; true" 
     else echo "g = $g; c = $c; false" 
     fi 
    done 
done 

Beispiel läuft, mit Bash 3.2.57 auf Mac OS X:

g = 1; c = 123; true 
g = 1; c = 456; false 
g = 1; c = 789; false 
g = 2; c = 123; false 
g = 2; c = 456; true 
g = 2; c = 789; false 
g = 3; c = 123; false 
g = 3; c = 456; false 
g = 3; c = 789; false 

Sie brauchen nicht die Variablen in [[ zu zitieren, wie Sie mit [ tun, weil es keinen separaten Befehl in der gleichen Weise, wie [ ist.


Ist es nicht eine klassische Frage?

Ich hätte das gedacht. Allerdings gibt es eine weitere Alternative ist, nämlich:

if [ "$g" -eq 1 -a "$c" = "123" ] || [ "$g" -eq 2 -a "$c" = "456" ] 
then echo abc 
else echo efg 
fi 

der Tat, wenn Sie die ‚portable Shell‘ Richtlinien für die autoconf Werkzeug oder verwandte Pakete lesen, diese Notation - ‚||‘ und ‚&&‘ mit - ist das, was sie empfehlen. Ich nehme an, Sie sogar so weit gehen könnte:

if [ "$g" -eq 1 ] && [ "$c" = "123" ] 
then echo abc 
elif [ "$g" -eq 2 ] && [ "$c" = "456" ] 
then echo abc 
else echo efg 
fi 

Wo die Aktionen so trivial, wie Echo sind, ist dies nicht schlecht. Wenn der zu wiederholende Aktionsblock mehrere Zeilen umfasst, ist die Wiederholung zu schmerzhaft und eine der früheren Versionen ist vorzuziehen - oder Sie müssen die Aktionen in eine Funktion umbrechen, die in den verschiedenen then Blöcken aufgerufen wird.

+0

Vielen Dank, \\ (funktioniert. Warum habe ich nicht die Antwort von anderen Websites gefunden? Isn Ist es eine klassische Frage? – user389955

+6

Es ist gut zu wissen, dass escaped Klammern arbeiten, als Nebenbemerkung: in diesem speziellen Fall werden die Klammern nicht einmal benötigt, da "-a" tatsächlich eine höhere Priorität hat als "-o" (im Gegensatz '&&' und '||' in der Shell - jedoch _inside_ 'bash'' [[...]] '_conditionals_,' && '_also_ hat eine höhere Priorität als' || '). Wenn Sie vermeiden wollten' - a' und '-o' für maximale Robustheit und Portabilität - was die [POSIX man-Seite selbst] (http://man.cx/test) suggeriert - Sie könnten _subshells_ auch für die Gruppierung verwenden:' if ([$ g -eq 1] && ["$ c" = "123"]) || ([$ g -eq 2] && ["$ c" = "456"]) ' – mklement0

120

In Bash:

if [[ ($g == 1 && $c == 123) || ($g == 2 && $c == 456) ]] 
+7

Definitiv der beste Ansatz in' bash' : In diesem speziellen Fall sind die Klammern nicht sogar benötigt, weil _inside_ '[[...]]' _conditionals_ '&&' tatsächlich eine höhere Priorität hat als '||' - anders als _anders_ solche Bedingungen. – mklement0

+0

Können wir herausfinden, welche Bedingung hier zusammenpasst? War es der eine in der ersten Klammer oder der andere? – Firelord

+1

@Firelord: Sie müssten die Bedingungen in eine 'if' /' else' Anweisung trennen und den Code zwischen 'then' und' fi' in eine Funktion einfügen, um eine Wiederholung zu vermeiden. In sehr einfachen Fällen können Sie eine 'case' Anweisung mit'; & 'fallthrough (in Bash 4) verwenden. –

6
$ g=3 
$ c=133 
$ ([ "$g$c" = "1123" ] || [ "$g$c" = "2456" ]) && echo "abc" || echo "efg" 
efg 
$ g=1 
$ c=123 
$ ([ "$g$c" = "1123" ] || [ "$g$c" = "2456" ]) && echo "abc" || echo "efg" 
abc 
+1

Das ist eine nutzlose Subshell. '{;}' könnte stattdessen verwendet werden. – phk

5

Seien Sie vorsichtig, wenn Sie Leerzeichen in String-Variablen haben und Sie auf die Existenz überprüfen. Achten Sie darauf, sie richtig zu zitieren.

if [ ! "${somepath}" ] || [ ! "${otherstring}" ] || [ ! "${barstring}" ] ; then 
+1

wenn wir die geschweiften Klammern nach dem Dollar-Symbol verwenden !! –

12

Mit /bin/bash folgenden funktioniert:

if [ "$option" = "Y" ] || [ "$option" = "y" ]; then 
    echo "Entered $option" 
fi 
0
#!/bin/bash 

current_usage=$(df -h | grep 'gfsvg-gfslv' | awk {'print $5'}) 
echo $current_usage 
critical_usage=6% 
warning_usage=3% 

if [ ${current_usage%?} -lt ${warning_usage%?} ]; then 
echo OK current usage is $current_usage 
elif [ ${current_usage%?} -ge ${warning_usage%?} ] && [ ${current_usage%?} -lt ${critical_usage%?} ]; then 
echo Warning $current_usage 
else 
echo Critical $current_usage 
fi 
+3

Willkommen bei Stack Overflow! Diese Frage sucht nach einer * Erklärung *, nicht nur nach funktionierendem Code. Ihre Antwort bietet keinen Einblick für den Fragesteller und kann gelöscht werden. Bitte [bearbeiten] um zu erklären, was die beobachteten Symptome verursacht. –

Verwandte Themen