web-dev-qa-db-ger.com

Sind doppelte eckige Klammern [[]] einfachen eckigen Klammern [] in Bash vorzuziehen?

Ein Mitarbeiter behauptete kürzlich in einer Codeüberprüfung, dass das Konstrukt [[ ]] In Konstrukten wie [ ] Vorzuziehen sei

if [ "`id -nu`" = "$someuser" ] ; then 
     echo "I love you madly, $someuser"
fi

Er konnte keine Begründung liefern. Ist dort eines?

479
Leonard

[[ Hat weniger Überraschungen und ist im Allgemeinen sicherer zu verwenden. Es ist jedoch nicht portabel - POSIX gibt nicht an, was es tut, und nur einige Shells unterstützen es (neben bash habe ich gehört, dass ksh es auch unterstützt). Zum Beispiel können Sie tun

[[ -e $b ]]

um zu testen, ob eine Datei existiert. Aber mit [ Müssen Sie $b Zitieren, weil es das Argument aufteilt und Dinge wie "a*" Erweitert (wobei [[ Es wörtlich nimmt). Das hat auch damit zu tun, wie [ Ein externes Programm sein kann und wie jedes andere Programm sein Argument erhält (obwohl es auch ein eingebautes sein kann, aber dann hat es immer noch nicht diese spezielle Behandlung).

[[ Hat auch einige andere nette Funktionen, wie reguläre Ausdrücke, die mit =~ Übereinstimmen, zusammen mit Operatoren, wie sie in C-ähnlichen Sprachen bekannt sind. Hier ist eine gute Seite darüber: Was ist der Unterschied zwischen test, [ Und [[? und Bash Tests

537

Verhaltensunterschiede

Einige Unterschiede zu Bash 4.3.11:

  • POSIX vs Bash-Erweiterung:

  • regelmäßiges Kommando gegen Magie

    • [ Ist nur ein regulärer Befehl mit einem seltsamen Namen.

      ] Ist nur ein Argument von [, Das die Verwendung weiterer Argumente verhindert.

      Ubuntu 16.04 hat tatsächlich eine ausführbare Datei unter /usr/bin/[, Die von coreutils bereitgestellt wird, aber die in Bash integrierte Version hat Vorrang.

      An der Art und Weise, wie Bash den Befehl analysiert, ändert sich nichts.

      Insbesondere ist < Eine Umleitung, && Und || Verketten mehrere Befehle, ( ) Erzeugen Subshells, sofern sie nicht durch \ Und die Word-Erweiterung maskiert werden passiert wie gewohnt.

    • [[ X ]] Ist ein einzelnes Konstrukt, mit dem X auf magische Weise analysiert werden kann. <, &&, || Und () Werden speziell behandelt, und die Regeln für die Wortteilung unterscheiden sich.

      Es gibt auch weitere Unterschiede wie = Und =~.

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

  • <

  • && Und ||

    • [[ a = a && b = b ]]: Wahr, logisch und
    • [ a = a && b = b ]: Syntaxfehler, && Als UND-Befehlstrennzeichen geparst cmd1 && cmd2
    • [ a = a -a b = b ]: Entspricht, wird aber von POSIX³ nicht mehr unterstützt
    • [ a = a ] && [ b = b ]: POSIX und zuverlässige Entsprechung
  • (

    • [[ (a = a || a = b) && a = b ]]: false
    • [ ( a = a ) ]: Syntaxfehler, () wird als Subshell interpretiert
    • [ \( a = a -o a = b \) -a a = b ]: Entspricht, aber () wird von POSIX nicht mehr unterstützt
    • { [ a = a ] || [ a = b ]; } && [ a = b ] POSIX-Äquivalent⁵
  • Wortteilung und Generierung von Dateinamen bei Erweiterungen (split + glob)

    • x='a b'; [[ $x = 'a b' ]]: True, Anführungszeichen werden nicht benötigt
    • x='a b'; [ $x = 'a b' ]: Syntaxfehler, erweitert auf [ a b = 'a b' ]
    • x='*'; [ $x = 'a b' ]: Syntaxfehler, wenn sich mehr als eine Datei im aktuellen Verzeichnis befindet.
    • x='a b'; [ "$x" = 'a b' ]: POSIX-Äquivalent
  • =

    • [[ ab = a? ]]: Wahr, weil es Mustervergleich (* ? [ Sind magisch). Wird nicht global auf Dateien im aktuellen Verzeichnis erweitert.
    • [ ab = a? ]: a? Glob wird erweitert. Dies kann je nach den Dateien im aktuellen Verzeichnis wahr oder falsch sein.
    • [ ab = a\? ]: Falsch, keine Glob-Erweiterung
    • = Und == Sind in [ Und [[ Gleich, aber == Ist eine Bash-Erweiterung.
    • case ab in (a?) echo match; esac: POSIX-Äquivalent
    • [[ ab =~ 'ab?' ]]: False⁴, verliert Magie mit ''
    • [[ ab? =~ 'ab?' ]]: Wahr
  • =~

    • [[ ab =~ ab? ]]: True, POSIX erweiterter regulärer Ausdruck match, ? Expandiert nicht glob
    • [ a =~ a ]: Syntaxfehler. Kein Bash-Äquivalent.
    • printf 'ab\n' | grep -Eq 'ab?': POSIX-Äquivalent (nur einzeilige Daten)
    • awk 'BEGIN{exit !(ARGV[1] ~ ARGV[2])}' ab 'ab?': POSIX-Äquivalent.

Empfehlung : Verwenden Sie immer [].

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

Wenn Sie [[ ]] Verwenden, haben Sie:

  • portabilität verlieren
  • den Leser zwingen, die Feinheiten einer anderen Bash-Erweiterung zu lernen. [ Ist nur ein regulärer Befehl mit einem seltsamen Namen, es ist keine spezielle Semantik beteiligt.

¹ Inspiriert von dem äquivalenten Konstrukt [[...]] In der Korn-Shell

² schlägt jedoch für einige Werte von a oder b fehl (wie + Oder index) und führt einen numerischen Vergleich durch, wenn a und b sieht aus wie Dezimalzahlen. expr "x$a" '<' "x$b" Umgeht beide.

³ und schlägt auch für einige Werte von a oder b wie ! Oder ( Fehl.

⁴ in Bash 3.2 und höher und vorausgesetzt, die Kompatibilität zu Bash 3.1 ist nicht aktiviert (wie bei BASH_COMPAT=3.1)

⁵ obwohl die Gruppierung (hier mit der Befehlsgruppe {...;} Anstelle von (...), Die eine unnötige Unterschale ausführen würde) als Shell || Und && Nicht erforderlich ist Operatoren (im Gegensatz zu den Operatoren || und &&[[...]] oder den Operatoren -o/-a[) gleicher Vorrang. Also wäre [ a = a ] || [ a = b ] && [ a = b ] Gleichbedeutend.

[[ ]] hat mehr Funktionen - ich schlage vor, Sie werfen einen Blick auf das Advanced Bash Scripting Guide für weitere Informationen, insbesondere das Extended Test Command Abschnitt in Kapitel 7. Tests .

Übrigens, wie der Leitfaden feststellt, [[ ]] wurde in ksh88 (der 1988er Version der Korn Shell) eingeführt.

55
anon

Von Welcher Komparator, Test, Klammer oder doppelte Klammer ist am schnellsten? ( http://bashcurescancer.com )

Die doppelte Klammer ist ein "zusammengesetzter Befehl", bei dem als Test und die einfache Klammer eingebaute Shell-Befehle sind (und in Wirklichkeit derselbe Befehl sind). Somit führen die einfache und die doppelte Klammer unterschiedlichen Code aus.

Die Test- und Einzelhalterung sind am portabelsten, da sie als separate und externe Befehle vorliegen. Wenn Sie jedoch eine remote moderne Version von BASH verwenden, wird die doppelte Klammer unterstützt.

9
f3lix

Eine typische Situation, in der Sie [[nicht verwenden können, befindet sich in einem Autotool-Skript configure.ac. Klammern haben eine spezielle und unterschiedliche Bedeutung. Daher müssen Sie test anstelle von [oder [- Beachten Sie diesen Test und [sind dasselbe Programm.

Wenn Sie Googles Styleguide :

Test, [und [[

[...]] reduziert Fehler, da zwischen [[und]] und [...]] keine Pfadnamenerweiterung oder Wortteilung stattfindet, wo dies nicht der Fall ist.

# This ensures the string on the left is made up of characters in the
# alnum character class followed by the string name.
# Note that the RHS should not be quoted here.
# For the gory details, see
# E14 at https://tiswww.case.edu/php/chet/bash/FAQ
if [[ "filename" =~ ^[[:alnum:]]+name ]]; then
  echo "Match"
fi

# This matches the exact pattern "f*" (Does not match in this case)
if [[ "filename" == "f*" ]]; then
  echo "Match"
fi

# This gives a "too many arguments" error as f* is expanded to the
# contents of the current directory
if [ "filename" == f* ]; then
  echo "Match"
fi
1
crizCraig