Frage Was ist der Unterschied zwischen doppelten und einzelnen eckigen Klammern in bash?


Ich habe mich nur gefragt, was genau der Unterschied zwischen

[[ $STRING != foo ]]

und

[ $STRING != foo ]

ist, abgesehen davon, dass letzteres posix-konform ist, in sh gefunden wird und das erstere eine Erweiterung ist, die in bash gefunden wird.


344
2017-08-09 21:11


Ursprung


stackoverflow.com/questions/13542832 - Ciro Santilli 新疆改造中心 六四事件 法轮功
Falls Sie sich auch Gedanken darüber gemacht haben, überhaupt keine Klammern zu verwenden, z. im Zusammenhang mit einem if Aussage, sehen mywiki.wooledge.org/BashPitfalls#if_.5Bgrep_foo_myfile.5D - Kev
auch, Von Ubuntus Dokumenten: wiki.ubuntu.com ... - radistao


Antworten:


Es gibt einige Unterschiede. Meiner Meinung nach sind einige der wichtigsten:

  1. [ ist in Bash und vielen anderen modernen Muscheln eingebaut. Das eingebaute [ ist ähnlich wie test mit der zusätzlichen Anforderung eines Closings ]. Die Builtins [ und test ahmen die Funktionalität nach /bin/[ und /bin/test zusammen mit ihren Einschränkungen, so dass Skripte rückwärtskompatibel wären. Die ursprünglichen ausführbaren Dateien bestehen hauptsächlich noch für die Kompatibilität mit POSIX und die Abwärtskompatibilität. Ausführen des Befehls type [ in Bash zeigt das an [ wird standardmäßig als eingebaut interpretiert. (Hinweis: which [ sucht nur nach ausführbaren Dateien auf der PFAD und ist äquivalent zu type -p [)
  2. [[ ist nicht so kompatibel, es wird nicht unbedingt mit was auch immer funktionieren /bin/sh verweist auf. So [[ ist die modernere Bash / Zsh / Ksh-Option.
  3. weil [[ ist in die Shell integriert und hat keine Legacy - Anforderungen, Sie brauchen sich keine Gedanken über die Worttrennung zu machen IFS Variable, um Variablen zu verwechseln, die mit Leerzeichen zu einem String ausgewertet werden. Daher müssen Sie die Variable nicht wirklich in doppelte Anführungszeichen setzen.

In den meisten Fällen ist der Rest nur eine schönere Syntax. Um mehr Unterschiede zu sehen, empfehle ich diesen Link zu einer FAQ-Antwort: Was ist der Unterschied zwischen Test, [und [[?. In der Tat, wenn Sie ernsthaft Bash Scripting sind, empfehle ich, das gesamte zu lesen Wikieinschließlich der FAQ, Fallstrickeund Führer. Der Testabschnitt vom Führungsabschnitt erklärt diese Unterschiede auch und warum der / die Autor (en) denken [[ ist eine bessere Wahl, wenn Sie sich nicht darum sorgen müssen, so tragbar zu sein. Die Hauptgründe sind:

  1. Sie müssen sich nicht darum kümmern, die linke Seite des Tests zu zitieren, damit sie tatsächlich als Variable gelesen wird.
  2. Du musst nicht weniger als und größer als entkommen < > mit umgekehrten Schrägstrichen, damit sie nicht als Eingabeumleitung ausgewertet werden, was einige Dinge durch das Überschreiben von Dateien beschädigen kann. Dies geht wieder zurück auf [[ Eingebaut sein. Wenn [(test) ein externes Programm ist, müsste die Shell eine Ausnahme in der Art der Auswertung machen < und > nur wenn /bin/test wird genannt, was keinen Sinn ergeben würde.

261
2017-08-09 21:56



Danke, der Link zur bash FAQ war was ich suchte (wusste nicht über diese Seite, danke). - 0x89
Ich habe deinen Beitrag mit diesen Informationen bearbeitet, aber [und test werden als Builtins ausgeführt. Die Builtins wurden entwickelt, um / bin / [und / bin / test zu ersetzen, mussten aber auch die Einschränkungen der Binaries reproduzieren. Der Befehl 'type' bestätigt, dass das eingebaute Objekt verwendet wird. 'which [' sucht nur nach ausführbaren Dateien im PATH und entspricht 'type -P [' - klynch


Zusamenfassend:

[ist eine Bash Eingebaut

[[]] sind Bash Schlüsselwörter

Schlüsselwörter: Schlüsselwörter sind wie Built-Ins, aber der Hauptunterschied besteht darin, dass spezielle Parsing-Regeln für sie gelten. Zum Beispiel ist [ist ein Bash-Built-In, während [[ist ein Bash-Schlüsselwort. Sie werden beide zum Testen verwendet, aber da [[ist ein Schlüsselwort und nicht ein eingebauter, profitiert es von einigen speziellen Parserregeln, die es viel einfacher machen:

  $ [ a < b ]
 -bash: b: No such file or directory
  $ [[ a < b ]]

Das erste Beispiel gibt einen Fehler zurück, da bash versucht, die Datei b an den Befehl [a] umzuleiten. Das zweite Beispiel tut tatsächlich, was Sie erwarten. Das Zeichen <hat nicht mehr die besondere Bedeutung des Dateiumleitungsoperators.

Quelle: http://mywiki.wooledge.org/BashGuide/CommandsAndArguments


108
2017-12-29 19:42



[ ist ein POSIX-Shell-Befehl; Es muss nicht eingebaut werden. ] ist nur ein Argument, nach dem dieser Befehl sucht, so dass die Syntax ausgeglichen ist. Der Befehl ist ein Synonym für test außer dass test sucht nicht nach einem Abschluss ]. - Kaz
Siehe hier: pubs.opengroup.org/onlinepubs/009695399/utilities/test.html - Kaz


Verhaltensunterschiede

Getestet in Bash 4.3.11:

  • POSIX vs Bash Erweiterung:

    • [  ist POSIX
    • [[ ist eine Bash-Erweiterung
  • regelmäßiger Befehl gegen Magie

    • [ ist nur ein normaler Befehl mit einem seltsamen Namen.

      ] ist nur ein Argument von [ das verhindert, dass weitere Argumente verwendet werden.

      Ubuntu 16.04 hat tatsächlich eine ausführbare Datei dafür /usr/bin/[ bereitgestellt von Coreutils, aber die Bash-integrierte Version hat Vorrang.

      Nichts wird in der Art verändert, wie Bash den Befehl analysiert.

      Im Speziellen, < ist Umleitung, && und || Verketten mehrerer Befehle, ( ) generiert Subshells, sofern nicht von \und die Worterweiterung geschieht wie üblich.

    • [[ X ]] ist ein einzelnes Konstrukt, das macht X magisch geparst werden. <, &&, || und () werden speziell behandelt, und Worttrennungsregeln sind unterschiedlich.

      Es gibt auch weitere Unterschiede wie = und =~.

    In Bashese: [ ist ein eingebauter Befehl und [[ ist ein Schlüsselwort: https://askubuntu.com/questions/445749/whats-the-difference-between-shell-builtin-and-shell-keyword

  • <

  • && und ||

    • [[ a = a && b = b ]]: wahr, logisch und
    • [ a = a && b = b ]: Syntax-Fehler, && als UND-Befehlseparator analysiert cmd1 && cmd2 
    • [ a = a -a b = b ]: Äquivalent, aber von POSIX nicht mehr unterstützt
    • [ a = a ] && [ b = b ]: POSIX-Empfehlung
  • (

    • [[ (a = a || a = b) && a = b ]]: falsch
    • [ ( a = a ) ]: Syntax-Fehler, () wird als Subshell interpretiert
    • [ \( a = a -o a = b \) -a a = b ]: Äquivalent, aber () wird von POSIX abgelehnt
    • ([ a = a ] || [ a = b ]) && [ a = b ] POSIX-Empfehlung
  • Wortteilung

    • x='a b'; [[ $x = 'a b' ]]: stimmt, Zitate werden nicht benötigt
    • x='a b'; [ $x = 'a b' ]: Syntaxfehler, expandiert zu [ a b = 'a b' ]
    • x='a b'; [ "$x" = 'a b' ]: Äquivalent
  • =

    • [[ ab = a? ]]: Wahr, weil es so ist Mustererkennung (* ? [ sind magisch). Glob expandiert nicht zu Dateien im aktuellen Verzeichnis.
    • [ ab = a? ]: a? glob expandiert. Dies kann abhängig von den Dateien im aktuellen Verzeichnis wahr oder falsch sein.
    • [ ab = a\? ]: falsch, nicht glob expansion
    • = und == sind in beiden gleich [ und [[, aber == ist eine Bash-Erweiterung.
    • printf 'ab' | grep -Eq 'a.': POSIX ERE entspricht
    • [[ ab =~ 'ab?' ]]: falsch, verliert Magie mit ''
    • [[ ab? =~ 'ab?' ]]: wahr
  • =~

    • [[ ab =~ ab? ]]: Wahr, POSIX erweiterter regulärer Ausdruck Spiel, ? expandiert nicht glob
    • [ a =~ a ]: Syntax-Fehler
    • printf 'ab' | grep -Eq 'ab?': POSIX-Äquivalent

Empfehlung

Ich bevorzuge es immer zu benutzen [].

Es gibt POSIX-Entsprechungen für jeden [[ ]] Konstrukt, das ich gesehen habe.

Wenn du benutzt [[ ]] Sie:

  • die Tragbarkeit verlieren
  • zwingt den Leser, die Feinheiten einer anderen Bash-Erweiterung zu lernen. [ist nur ein regulärer Befehl mit einem seltsamen Namen, es sind keine speziellen Semantiken beteiligt.

61
2017-07-12 10:22



Wie benutzt man printf 'ab' | grep -Eq 'ab?' innerhalb if [ … ]? - meeDamian
@meeDamian if ( printf 'ab' | grep -Eq 'a' ); then echo 'a'; fi. [] ist ein Befehl wie grep. Das () möglicherweise nicht auf diesem Befehl benötigt werden Ich bin mir nicht sicher: Ich habe es wegen der hinzugefügt |, hängt davon ab, wie Bash die Dinge analysiert. Wenn es keine gab | Ich bin sicher, du kannst nur schreiben if cmd arg arg; then. - Ciro Santilli 新疆改造中心 六四事件 法轮功
@ MeeDamian ja, keine Notwendigkeit für () es scheint: stackoverflow.com/questions/8965509/... - Ciro Santilli 新疆改造中心 六四事件 法轮功
Schöne Liste! Siehe auch: wiki.ubuntu.com ... - radistao


Basierend auf einem schnellen Lesen der relevanten Abschnitte der Manpage scheint der Hauptunterschied darin zu bestehen, dass der == und != Operatoren stimmen mit einem Muster und nicht mit einer Literalfolge überein, und außerdem gibt es die =~ Regex Vergleichsoperator.


4
2017-08-09 21:17





Einzelhalterung d.h. [] ist POSIX-Shell kompatibel, um einen bedingten Ausdruck zu umschließen.

Doppelwinkel d.h. [[]] ist eine erweiterte (oder erweiterte) Version der POSIX-Standardversion, die von bash und anderen Shells (zsh, ksh) unterstützt wird.

In bash, für den numerischen Vergleich verwenden wir eq, ne,lt und gt, mit doppelten Klammern zum Vergleich können wir verwenden ==, !=, <, und > buchstäblich.

  • [ ist ein Synonym für Testbefehl. Selbst wenn es in die Shell eingebaut ist, erzeugt es einen neuen Prozess.
  • [[ ist eine neue verbesserte Version davon, die ein Schlüsselwort ist, kein Programm.

zum Beispiel:

[ var1 lt var2] #works
[ var1 < var2] #error: var2 No such file or directory 
[ var1 \< var2] #works with escape
[[ var1 < var2]] #works

3
2018-02-08 03:15