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?
[[
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
Verhaltensunterschiede
Einige Unterschiede zu Bash 4.3.11:
POSIX vs Bash-Erweiterung:
[
ist POSIX[[
Ist eine Bash-Erweiterung¹, die dokumentiert ist unter: https://www.gnu.org/software/bash/manual/bash.html#Conditional-Constructsregelmäß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
<
[[ a < b ]]
: Lexikografischer Vergleich[ a \< b ]
: Wie oben. \
Erforderlich oder leitet wie bei jedem anderen Befehl um. Bash-Erweiterung.expr a \< b > /dev/null
: POSIX-Äquivalent², siehe: Wie teste ich Strings auf lexikografische Werte kleiner oder gleich in Bash?&&
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ötigtx='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:
[
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.
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.
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