Betrachten Sie zwei bedingte Ausdrücke expr1
und expr2
zum Beispiel $i -eq $j
und $k -eq $l
. Wir können dies auf verschiedene bash
Arten schreiben . Hier sind zwei Möglichkeiten
[[ expr1 || expr2 ]]
[[ expr1 ]] || [[ expr2 ]]
Ich bin mir ziemlich sicher, dass ich hier Empfehlungen gesehen habe, dass die zweite bevorzugt werden sollte, aber ich kann keine Beweise finden, die dies unterstützen.
Hier ist ein Beispielskript, das zu demonstrieren scheint, dass es keinen Unterschied gibt:
for i in 0 1
do
for j in 0 1
do
for k in 0 1
do
for l in 0 1
do
if [[ $i -eq $j || $k -eq $l ]]; then printf "1-yes\t"; else printf "1-no\t"; fi
if [[ $i -eq $j ]] || [[ $k -eq $l ]]; then printf "2-yes\n"; else printf "2-no\n"; fi
done
done
done
done
und Ausgabe, die zeigt, dass beide Bedingungskonstrukte das gleiche Ergebnis erzeugen:
1-yes 2-yes
1-yes 2-yes
1-yes 2-yes
1-yes 2-yes
1-yes 2-yes
1-no 2-no
1-no 2-no
1-yes 2-yes
1-yes 2-yes
1-no 2-no
1-no 2-no
1-yes 2-yes
1-yes 2-yes
1-yes 2-yes
1-yes 2-yes
1-yes 2-yes
Gibt es einen Vorteil bei der Verwendung eines Konstrukts gegenüber dem anderen?
Für Bonuspunkte dieselbe Frage, aber Verallgemeinerung auf mehrere Bedingungen mit ||
und &&
. Zum Beispiel [[ expr1 && expr2 || expr3 ]]
.
[
odertest
( nicht[[
) suchen Sie nach denOB
Tags (verknüpft mit der "veralteten" Definition) in der POSIX-Spezifikation fürtest
. Intest
einigen pathologischen Fällen kann es unmöglich sein zu sagen, ob(
oder)
soll eine Syntax sein, die für den Testbefehl oder eine zu testende Zeichenfolge von Bedeutung ist. Daher können Personen, die die Veralterungsmarkierungen ignorieren und diese Syntax verwenden, tatsächlich das Gegenteil benötigen. veraltete"x$foo"
Praxis; mit[[
, das ist kein problem.Antworten:
Ich denke, die Empfehlung, die Sie gesehen haben, war für POSIX sh und / oder den
test
Befehl, der gleichzeitig als[
Befehl fungiert, und nicht für das[[
Konstrukt, das in ksh erschien (danke Stéphane Chazelas für den Tipp) und das auch zum Beispiel in bash, zsh und einigen anderen verwendet wird Muscheln.In den meisten Sprachen wie C müssen die verbleibenden Teile je nach Operation nicht ausgewertet werden, wenn eine Klausel bereits als wahr oder falsch bekannt ist: Wenn wahr, nicht nach einer logischen oder nach ihr, wenn falsch, nicht nach einer logischen und , usw. Dies ermöglicht es beispielsweise, anzuhalten, wenn ein Zeiger NULL ist, und nicht zu versuchen, ihn in der nächsten Klausel zu dereferenzieren.
Aber sh ‚s -
[ expr1 -o expr2 ]
Konstrukt (einschließlich bash-Implementierung) tut dies nicht: Es wertet immer beiden Seiten, wenn man wollen würde nur ausdr1 ausgewertet werden. Dies wurde möglicherweise aus Gründen der Kompatibilität mit dertest
Befehlsimplementierung durchgeführt. Auf der anderen Seite folgen shs||
und&&
do dem üblichen Prinzip: nicht bewertet, wenn es das Ergebnis nicht ändert.Der zu beachtende Unterschied wäre also:
was ergibt:
Oben
[
könnte jeder durch/usr/bin/[
einen Alias für dentest
Befehl ersetzt worden sein, der zuvor[
in Shells eingebaut wurde.Während die beiden nächsten Konstrukte:
oder
Wird nur nachgeben
true
undeffect
leer lassen:||
verhält sich korrekt und hat auch[[
dieses Problem behoben.AKTUALISIEREN:
Wie @ StéphaneChazelas kommentierte, habe ich einige Unterschiede in Bezug auf die ursprüngliche Frage übersehen. Ich werde hier nur das Wichtigste (zumindest für mich) nennen: die Priorität der Betreiber.
Während die Shell keinen Vorrang hat:
Ausbeuten (weil es keinen Vorrang gibt und somit zuerst
true || true
ausgewertet wird und dann&& false
):innerhalb
[[ ]]
des&&
Operators hat Vorrang vor||
:ergibt (weil
1 -eq 1 && 1 -eq 0
gruppiert ist und somit das 2. Mitglied von ist||
):Zumindest für ksh , bash , zsh .
Das
[[ ]]
Verhalten gegenüber[ ]
logischen Shell-Operatoren und direkten Shell-Operatoren wurde verbessert .quelle
[ x -o y ]
muss nicht beide Seiten bewerten. Während GNUtest
oder das[
eingebaute vonbash
do, würden Siestrace zsh -c '[ x -o -f /x ]'
damit[
nicht versuchen, stat ()/x
. Gleiches gilt fürmksh
. Aber es ist wahr, dass-o
und-a
schwer beschädigt, nicht zuverlässig verwendet werden können und von POSIX veraltet sind.[[...]]
,&&
hat eine höhere Priorität als||
, während außerhalb sie gleich Vorrang haben. Vergleicheksh -c '[[ x || x && "" ]]'
vssh -c 'true || true && false'
[
/ dastest
Dienstprogramm keinen==
Operator hat. Der Gleichheitsoperator ist=
(beachten Sie, dass innerhalb KSH ist[[...]]
,=
/==
sind nicht Gleichheitsoperatoren, sondern Musterabgleich sind).&&
hat Vorrang vor||
innen[[...]]
(oder((...))
) , aber die nicht&&
und||
Shell - Operatoren.[[ x || y && z ]]
isx || (y && z)
whilex || y && z
is(x || y) && z
(Operatoren werden von links nach rechts ohne Vorrang ausgewertet). Ähnlich wie*
hat Vorrang vor+
(1 + 2 * 3
ist1 + (2 * 3)
), aber+
und-
haben den gleichen Vorrang.&&
Vorrang vor hat||
, sollte estrue || (true && false)
statt(true || true) && false