Verwenden Sie in einem Bash-Skript die Bedingung "oder" in einer "if" -Anweisung

129

Diese Frage ist eine Art Fortsetzung meiner früheren Frage . Die Benutzer auf dieser Site haben mir freundlicherweise dabei geholfen, herauszufinden, wie eine Bash- forSchleife geschrieben wird, die Zeichenfolgenwerte durchläuft. Angenommen, eine Schleifensteuerungsvariable fnamedurchläuft die Zeichenfolgen "a.txt" "b.txt" "c.txt". Ich würde gerne echo"Ja!" wann fnamehat der Wert "a.txt"oder "c.txt"und echo"nein!" Andernfalls. Ich habe das folgende Bash-Shell-Skript ausprobiert:

#!/bin/bash

for fname in "a.txt" "b.txt" "c.txt"
do
 echo $fname
 if [ "$fname" = "a.txt" ] | [ "$fname" = "c.txt" ]; then
 echo "yes!"
else
 echo "no!"
fi
done

Ich erhalte die Ausgabe:

a.txt

Nein!

b.txt

Nein!

c.txt

Ja!

Warum ist die ifAussage anscheinend wahr, wenn fnamesie den Wert hat "a.txt"? Habe ich |falsch benutzt?

Andrew
quelle
3
In der Bash ist 'oder' Operator '||' (C-Stil).
Marius Cotofana
3
Sie können auch -oinnerhalb desselben verwenden [ ].
Thor
6
@Thor Ich würde es vorziehen , ||und trennen [ ]über -oeinfach für Portabilität , weil [nicht gewährleistet ist, um mehr als 4 Argumente zu unterstützen. Natürlich, wenn die Zielsprache ist bash, sollte niemand [sowieso verwenden, weil bash's [[in vielerlei Hinsicht überlegen ist.
JW013
2
@ jw013 Danke. Bedeutet das, dass ich if [[ "$fname" = "a.txt" ]] || [[ "$fname" = "c.txt" ]]eher verwenden sollte als if [ "$fname" = "a.txt" ] || [ "$fname" = "c.txt" ]?
Andrew
5
@ Andrew Das ist richtig, wenn Sie den Shebang als deklarieren bash, wie Sie es bereits tun. Ein Vorteil von [[ist, dass es keine Worttrennung (Sonderfall) macht, also [[ $unquoted_var = string ]]sicher ist.
jw013

Antworten:

229

Wenn du sagen willst, ORbenutze double pipe ( ||).

if [ "$fname" = "a.txt" ] || [ "$fname" = "c.txt" ]

(Der ursprüngliche OP-Code, der verwendet |wurde, leitete einfach den Ausgang der linken Seite zur rechten Seite, auf die gleiche Weise, wie jede gewöhnliche Pipe funktioniert.)

Bahamat
quelle
4
Darüber hinaus wird ||keine Standardlogik "ODER" ausgeführt - es wird kurzgeschlossen, und der zweite Befehl wird nur ausgeführt, wenn der erste fehlschlägt.
Holdenweb
13
@holdenweb Ich bin mir ziemlich sicher, dass die meisten modernen optimierten Sprachen genauso funktionieren. Es ist nicht erforderlich, CPU-Zyklen damit zu verbringen, die zweite Bedingung ORzu bewerten, wenn die erste Bedingung wahr ist.
Bahamat
1
Ich dachte, Bash mochte, ==aber nachdem ich diese Antwort gesehen hatte, beschloss ich, nachzuschlagen. Anscheinend "kann es verwendet werden, ist aber nicht Standard". Ich dachte, ich würde dies für andere hier setzen, wenn Sie neugierig sind: stackoverflow.com/a/2237103
harperville
Dies ist, was die testManpage auch empfiehlt
cdosborn
2
Sie können auch Doppelklammertests verwenden if [[ "$fname" = "a.txt" ]] || [[ "$fname" = "c.txt" ]](wenn Sie zusätzliche Funktionen benötigen oder möchten [[ ]]).
HankCa