Warum verhält sich == == innerhalb von […] in zsh und bash anders?

9

Ich bekomme, was ich erwartet habe, wenn ich das mache in bash:

[ "a" == "a" ] && echo yes

Es gab mir yes.

Aber wenn ich das mache zsh, bekomme ich folgendes:

zsh: = not found

Warum verhält sich derselbe Befehl ( /usr/bin/[) in verschiedenen Shells unterschiedlich?

Johnson Steward
quelle
5
Es ist nicht der gleiche Befehl - es ist ein eingebauter Befehl, der zuvor $PATHdurchsucht wurde. und ==ist keine gültige testSyntax für den /usr/bin/[Weg. Ist einfach =in Ordnung.
Mikeserv

Antworten:

18

Es ist nicht /usr/bin/[in einer der Muscheln. In Bash, verwenden Sie den eingebauten in test/ [Befehl , und in ähnlicher Weise in zsh .

Der Unterschied besteht darin, dass zsh auch eine =Erweiterung hat : Erweitert=foo den Pfad zur fooausführbaren Datei. Das bedeutet, dass ==versucht wird, einen Befehl zu finden, der =in Ihrem aufgerufen wirdPATH . Da dieser Befehl nicht vorhanden ist, wird der Fehler angezeigt

zsh: = not found

dass Sie gesehen haben (und in der Tat würde das gleiche passieren, selbst wenn Sie tatsächlich verwenden /usr/bin/[).


Sie können verwenden ==hier , wenn Sie wirklich wollen. Dies funktioniert wie in zsh erwartet:

[ "a" "==" "a" ] && echo yes

weil das Zitat verhindert, dass die =wordErweiterung ausgeführt wird. Sie können die equalsOption auch mit deaktivieren setopt noequals.


Sie wären jedoch auch besser dran:

  • Mit single =den POSIX-kompatiblen Gleichheitstest ; oder
  • Besser noch, die [[Bedingungen mit== sowohl in Bash als auch in zsh zu verwenden . Im Allgemeinen [[ist es einfach besser und sicherer, einschließlich der Vermeidung dieser Art von Problemen (und anderer) durch spezielle Parsing-Regeln.
Michael Homer
quelle
Was ist der genaue Unterschied zwischen [und [[? (Die Suche bei Google nach [ vs [[gibt mir nur Ergebnisse für vsLOL)
Johnson Steward
2
[[unterstützt in beiden Fällen eine größere Auswahl an Tests und verfügt über benutzerdefinierte Analyseregeln, die das Zitieren von Variablen, Operatoren usw. vermeiden. Wenn Sie speziell entweder Bash oder zsh verwenden, verwenden Sie [[. Wenn Sie ein portables Skript schreiben, schreiben Sie in den POSIX-kompatiblen Befehl [/ test(der auf Ihrem laufenden System möglicherweise ein echter Befehl ist oder nicht).
Michael Homer
1
Einfach [[dort verwenden und vergessen [existiert.
Michael Homer
1
Sie wissen, ich bin mit Ihrer Empfehlung nicht einverstanden. [[ist anders fähig. versuchen Sie dies damit : for f in *; do [ -e "$f" ] && for a in f d h p S b c; do [ "-$a" "$f" ] && for p in r w x u g; do [ "-$p" "$f" ] || p=-; a=$a$p; done && break; done && printf "%s:\t%s\n" "$a" "$f"; done.
Mikeserv
3
Nun, =/ ==ist wohl ein Fall , in dem [[besser ist , nicht als [, wie [[ a == b ]]ist tut „a“ entsprechen die „b“ Muster und nicht „a“ ist gleich „b“ , wie man erwarten würde. Das heißt, Sie müssen zum Beispiel schreiben [[ $a == "$b" ]]. [Wenn Sie mit dem Befehl wissen, wie das Parsen von [ "$a" = "$b" ]Befehlen funktioniert, müssen Sie ihn zumindest schreiben , um den Operator split + glob wie in anderen Befehlen zu verhindern. In diesem Sinne und wenn Sie -a oder -o nicht verwenden, [ist dies in POSIX-konformen Implementierungen sicher.
Stéphane Chazelas
2

Und zsh und bash geben die gleiche Antwort ( typeist auch für beide Shells eingebaut):

$ type -a [
[ is a shell builtin
[ is /usr/bin/[
Jshura
quelle
2

[ ist ein Shell-Befehl in bash und in zsh:

$ type [
[ is a shell builtin

Aus der Dokumentation zu Shell Builtin Commands :

Eingebaute Befehle sind in der Shell selbst enthalten . Wenn der Name eines eingebauten Befehls als erstes Wort eines einfachen Befehls verwendet wird (siehe Einfache Befehle ), führt die Shell den Befehl direkt aus, ohne ein anderes Programm aufzurufen. Eingebaute Befehle sind erforderlich, um Funktionen zu implementieren, die mit separaten Dienstprogrammen nicht oder nur ungünstig verfügbar sind.

Die offizielle Dokumentation ( $ help test) erlaubt nur die Verwendung von =:

STRING1 = STRING2

True, wenn die Zeichenfolgen gleich sind.

Der richtige Ausdruck wäre also:

$ [ "a" = "a" ] && echo yes
yes

Was passiert ist, dass Bash etwas weniger streng ist. Die Unterstützung des ==Bedieners mit [ scheint eine Bash-Erweiterung zu sein, und es wird nicht empfohlen, sie zu verwenden:

string1 == string2

string1 = string2

True, wenn die Zeichenfolgen gleich sind. Bei Verwendung mit dem Befehl [[führt dies einen Mustervergleich wie oben beschrieben durch (siehe Bedingte Konstrukte ).

'=' sollte mit dem Testbefehl für die POSIX-Konformität verwendet werden.

Wenn Sie verwenden möchten ==, sollten Sie das [[Schlüsselwort verwenden:

$ [[ "a" == "a" ]] && echo yes
yes

Beachten Sie, dass dies [[weniger portabel ist (nicht POSIX). Aber sowohl bash als auch zsh unterstützen es.

zuazo
quelle
1

In beiden Shells bashund zshist das [Dienstprogramm eine integrierte Shell. Dies ist die Shells-Implementierung dieses Tools, die der Binärdatei vorgezogen wird /usr/bin/[. Die unterschiedlichen Ergebnisse werden durch unterschiedliche Implementierungen verursacht.


In akzeptiert bashdas [Dienstprogramm CONDITIONAL EXPRESSIONSals [[zusammengesetzten Befehl. Laut Bashs Manpage sind beide =und ==gültig:

string1 == string2
string1 = string2
        True if the strings are equal.  = should be used with the test command for POSIX
        conformance.

In zshversucht das [Dienstprogramm, POSIX und seine Erweiterungen dort zu implementieren, wo diese angegeben sind. In der Spezifikation des POSIX-Testdienstprogramms ist kein ==Operator definiert.

Chaos
quelle