Was ist die Syntax einer komplexen Bedingung in der Shell?

10

Wenn Sie den folgenden Test in Shell (sh) ausdrücken möchten:

if ( a == 1 && ( b == 1 || b == 2 )) { ... }

Das Beste, was ich bisher schreiben konnte, ist Folgendes:

if [[ $a -eq 1 ]]; then
  if [[ $b -eq 1 || $b -eq 2 ]]; then
     ...
  fi
fi

Ich weiß nicht, wie ich && und || zusammensetzen soll mit korrekter Priorität. Googeln hat mir keine Antwort gegeben (Tutorials geben nur grundlegende Beispiele, falls vorhanden)

Was ist die Syntax die beiden zu kombinieren , wenn in einem?

Offirmo
quelle
1
Gibt es einen Grund, nicht zu verwenden ksh? Dann würde Ihr anfänglicher Code nur noch ein Paar Klammern erfordern:if (( a == 1 && ( b == 1 || b == 2 ))); then :; fi
Manatwork

Antworten:

14

Beachten Sie, dass dies [[ ]]weder in Bourne noch in POSIX der Fall ist sh. Für eine echte shSyntax gibt es verschiedene Möglichkeiten.

Verwenden Sie nur ein [ ]Paar

if [ 1 -eq "$a" -a \( 1 -eq "$b" -o 2 -eq "$b" \) ]; then
    # ...
fi

oder Vermeiden von POSIX -aund -oOptionen 1

if [ 1 -eq "$a" ] && { [ 1 -eq "$b" ] || [ 2 -eq "$b" ]; }; then
    # ...
fi

1 Ein Grund für die Vermeidung -aund -omaximale Portabilität: Nicht alle testoder [Implementierungen können mehr als 4 Argumente verarbeiten. Genau das erhalten Sie, wenn Sie Ausdrücke mit -aund -ound verketten \( \).

jw013
quelle
Meine Skripte haben das #! / bin / sh shebang und die Standard-Shell ist ksh . Warum sollte sh nicht verwendet werden?
Offirmo
2
@Offirmo Wenn Sie Ihr Skript als deklarieren /bin/sh, ist es falsch, das Skript mit Funktionen zu schreiben, die nicht in enthalten sind sh. Sie sollten sich bewusst sein, dass dies kshNICHT ist sh, sondern eine Obermenge von sh. Wenn Sie Ihr kshals shSkript deklariertes Skript zu einem System bringen, zu dem shkein Symlink besteht, kshkann es beschädigt werden . Sie können dieses Problem vermeiden, indem Sie sicherstellen, dass Ihr Skript mit der Deklaration übereinstimmt.
jw013
Ich dachte, dass das Setzen von / bin / sh als shebang meine Skripte über / bin / sh aufrufen würde . Meinen Sie damit, dass meine Standard-Shell (ksh) den Shebang ignoriert und direkt interpretiert?
Offirmo
@Offirmo Sie haben Recht: Ein Schebang des /bin/shWillens ruft /bin/sh. Das Problem ist /bin/shnicht zu akzeptieren [[. Sie können entweder keine [[Shell verwenden oder verwenden [[, die z. B. kshals Shebang akzeptiert .
jw013
2
Das Problem ist nicht so sehr, dass -a/ -owerden von einigen Implementierungen nicht unterstützt, aber dass es für beliebige Argumente nicht zuverlässig ist. Like [ "$a" = "$b" -o "$b" = "$c" ]würde bei vielen Implementierungen für Werte von $alike fehlschlagen . ![
Stéphane Chazelas
2

Ich habe eine Syntax ausprobiert und das gefunden

if [[ $a -eq 1 ]] && [[ $b -eq 1 || $b -eq 2 ]]; then
 ...
fi

funktioniert.

Offirmo
quelle
1
Dies funktioniert für Bash-Version über 4.
Nikhil Mulley
2

Ein weiterer POSIX-Ansatz:

if [ "$((a == 1 && ( b == 1 || b == 2 )))" -ne 0 ]; then
  ...
fi
Stéphane Chazelas
quelle
0

Der richtige Weg, es mit einem bloßen zu tun shell:

if test 1 -eq "$a" && test 1 -eq "$b" -o 2 -eq "$b"; then 
    ...
fi

Erläuterung:

testhier dient als Klammer und -oals logisches oder. Wenn Sie eine logische und innerhalb der "Klammer" würden Sie verwenden -a.

Mehr dazu finden Sie hier

Omer Dagan
quelle