Dies ist ein sehr undurchsichtiger Eckfall, bei dem man einen Fehler in der [
Definition des integrierten Tests in Betracht ziehen könnte . Es entspricht jedoch dem Verhalten der tatsächlichen [
Binärdatei, die auf vielen Systemen verfügbar ist. Soweit ich sagen kann, es wirkt sich nur auf bestimmte Fälle und eine Variable einen Wert hat, eine übereinstimmt [
Operator wie (
, !
, =
, -e
, und so weiter.
Lassen Sie mich erklären, warum und wie man es in Bash- und POSIX-Shells umgeht.
Erläuterung:
Folgendes berücksichtigen:
x="("
[ "$x" = "(" ] && echo yes || echo no
Kein Problem; das obige ergibt keinen Fehler und gibt aus yes
. So erwarten wir, dass Dinge funktionieren. Sie können die Vergleichszeichenfolge '1'
wie gewünscht und den Wert von in ändern x
, und es funktioniert wie erwartet.
Beachten Sie, dass sich die eigentliche /usr/bin/[
Binärdatei genauso verhält. Wenn Sie zB laufen'/usr/bin/[' '(' = '(' ']'
liegt kein Fehler vor, da das Programm erkennen kann, dass die Argumente aus einer einzelnen Zeichenfolgenvergleichsoperation bestehen.
Der Fehler tritt auf, wenn wir und mit einem zweiten Ausdruck. Es spielt keine Rolle, was der zweite Ausdruck ist, solange er gültig ist. Beispielsweise,
[ '1' = '1' ] && echo yes || echo no
gibt aus yes
und ist offensichtlich ein gültiger Ausdruck; aber wenn wir die beiden kombinieren,
[ "$x" = "(" -a '1' = '1' ] && echo yes || echo no
Bash lehnt den Ausdruck , wenn und nur wenn x
ist (
oder!
.
Wenn wir das oben genannte unter Verwendung des tatsächlichen [
Programms ausführen würden , d.h.
'/usr/bin/[' "$x" = "(" -a '1' = '1' ] && echo yes || echo no
Der Fehler wäre verständlich: Da die Shell die Variablensubstitutionen ausführt, die /usr/bin/[
Binärdatei nur Parameter empfängt (
=
(
-a
1
=
1
und beendet ]
, kann sie verständlicherweise nicht analysieren, ob die offenen Klammern einen Unterausdruck beginnen oder nicht, da ein und vorhanden ist -Operation beteiligt ist. Sicher, das Parsen als zwei Zeichenfolgenvergleiche ist möglich, aber wenn Sie dies gierig tun, kann dies zu Problemen führen, wenn es auf korrekte Ausdrücke mit in Klammern gesetzten Unterausdrücken angewendet wird.
Das eigentliche Problem ist, dass sich die [
eingebaute Shell genauso verhält, als würde sie den Wert von x
vor der Prüfung des Ausdrucks erweitern.
(Diese und andere Unklarheiten im Zusammenhang mit der Variablenerweiterung waren ein wichtiger Grund für die Implementierung von Bash und empfehlen nun, stattdessen die [[ ... ]]
Testausdrücke zu verwenden.)
Die Problemumgehung ist trivial und wird häufig in Skripten mit älteren sh
Shells verwendet. Sie fügen häufig ein "sicheres" Zeichen x
vor die Zeichenfolgen ein (beide Werte werden verglichen), um sicherzustellen, dass der Ausdruck als Zeichenfolgenvergleich erkannt wird:
[ "x$x" = "x(" -a "x$y" = "x1" ]
[[ "$x" = '1' && "$y" = '1' ]]