Ich habe mich nur gefragt, was genau der Unterschied ist
[[ $STRING != foo ]]
und
[ $STRING != foo ]
ist, abgesehen davon, dass das letztere posix-konform ist, gefunden in sh und das erstere ist eine Erweiterung, die in bash gefunden wird.
Ich habe mich nur gefragt, was genau der Unterschied ist
[[ $STRING != foo ]]
und
[ $STRING != foo ]
ist, abgesehen davon, dass das letztere posix-konform ist, gefunden in sh und das erstere ist eine Erweiterung, die in bash gefunden wird.
Antworten:
Es gibt verschiedene Unterschiede. Meiner Meinung nach sind einige der wichtigsten:
[
ist eine eingebaute in Bash und viele andere moderne Muscheln. Das eingebaute [
ähnelt test
mit dem zusätzlichen Erfordernis eines Schließens ]
. Die eingebauten [
und test
imitierten Funktionen /bin/[
und /bin/test
deren Einschränkungen, so dass Skripte abwärtskompatibel wären. Die ursprünglichen ausführbaren Dateien sind größtenteils noch aus Gründen der POSIX-Kompatibilität und Abwärtskompatibilität vorhanden. Wenn Sie den Befehl type [
in Bash [
ausführen, wird dies standardmäßig als eingebaut interpretiert. (Hinweis: Sucht which [
nur nach ausführbaren Dateien auf dem Pfad und ist äquivalent zu type -p [
)[[
ist nicht so kompatibel, es wird nicht unbedingt funktionieren mit welchen /bin/sh
Punkten auch immer . So [[
ist die modernere Bash / Zsh / Ksh-Option.[[
in die Shell integriert ist und keine älteren Anforderungen stellt, müssen Sie sich keine Gedanken über die Wortteilung auf der Grundlage der IFS- Variablen machen, um Variablen durcheinanderzubringen, die als Zeichenfolge mit Leerzeichen ausgewertet werden. Daher müssen Sie die Variable nicht in doppelte Anführungszeichen setzen.Der Rest ist größtenteils nur eine nette Syntax. Um weitere Unterschiede zu sehen, empfehle ich diesen Link zu einer FAQ-Antwort: Was ist der Unterschied zwischen test, [und [[? . In der Tat empfehle ich, wenn Sie es mit Bash-Skripten ernst meinen, das gesamte Wiki zu lesen , einschließlich der FAQ, Fallstricke und Anleitung. Der Testabschnitt aus dem Handbuchabschnitt erklärt auch diese Unterschiede und warum die Autoren der Meinung [[
sind, dass dies die bessere Wahl ist, wenn Sie sich keine Gedanken über die Mobilität machen müssen. Die Hauptgründe sind:
< >
mit Backslashes umgehen, damit sie nicht als Eingabeumleitung gewertet werden, was einige Dinge durch das Überschreiben von Dateien durcheinander bringen kann. Dies geht wieder zurück zu [[
einem eingebauten. Wenn [(test) ein externes Programm ist, müsste die Shell in der Art <
und Weise, wie sie ausgewertet wird, eine Ausnahme machen und >
nur, wenn /bin/test
es aufgerufen wird, was eigentlich keinen Sinn ergibt.Zusamenfassend:
[ist eine Bash Builtin
[[]] sind bash Keywords
Schlüsselwörter: Schlüsselwörter sind wie integrierte Schlüsselwörter, der Hauptunterschied besteht jedoch darin, dass für sie spezielle Analyseregeln gelten. Beispiel: [ist eine integrierte Bash, während [[ein Bash-Schlüsselwort ist. Sie werden beide zum Testen von Dingen verwendet, aber da [[kein eingebautes, sondern ein Schlüsselwort ist, profitieren sie von einigen speziellen Parsing-Regeln, die es viel einfacher machen:
$ [ a < b ]
-bash: b: No such file or directory
$ [[ a < b ]]
Das erste Beispiel gibt einen Fehler zurück, weil bash versucht, die Datei b an den Befehl [a] umzuleiten. Das zweite Beispiel macht tatsächlich das, was Sie erwarten. Das Zeichen <hat keine spezielle Bedeutung mehr für den Operator "Dateiumleitung".
Quelle: http://mywiki.wooledge.org/BashGuide/CommandsAndArguments
[
ist ein POSIX-Shell-Befehl; Es muss nicht eingebaut werden. Es ]
ist nur ein Argument, nach dem dieser Befehl sucht, damit die Syntax ausgewogen ist. Der Befehl ist ein Synonym für, test
außer dass er test
nicht nach einem Abschluss sucht ]
.
Verhaltensunterschiede
Einige Unterschiede zu Bash 4.3.11:
POSIX vs Bash-Erweiterung:
[
ist POSIX[[
ist eine Bash-Erweiterung¹, die unter https://www.gnu.org/software/bash/manual/bash.html#Conditional-Constructs dokumentiert istRegelmäßiges Kommando gegen Magie
[
ist nur ein regulärer Befehl mit einem seltsamen Namen.
]
Dies ist nur ein Argument [
, das die Verwendung weiterer Argumente verhindert.
Ubuntu 16.04 hat tatsächlich eine ausführbare Datei, /usr/bin/[
die von coreutils zur Verfügung gestellt wird, aber die in Bash integrierte Version hat Vorrang.
An der Art und Weise, wie Bash den Befehl analysiert, ändert sich nichts.
Insbesondere werden durch <
Umleitung &&
und ||
Verketten mehrerer Befehle ( )
Unterschalen generiert, sofern diese nicht durch Escapezeichen geschützt werden \
, und die Worterweiterung erfolgt wie gewohnt.
[[ X ]]
ist ein einzelnes Konstrukt, das X
magisch analysiert werden kann. <
, &&
, ||
Und ()
sind speziell, und einzelne Wörter aufgespalten Regeln behandelt unterschiedlich.
Es gibt auch weitere Unterschiede wie =
und =~
.
In Bashese: [
ist ein integrierter Befehl und [[
ein Schlüsselwort: https://askubuntu.com/questions/445749/was ist der Unterschied zwischen dem eingebauten Shell- und dem Shell - Schlüsselwort ?
<
[[ a < b ]]
: lexikographischer Vergleich[ a \< b ]
: Das gleiche wie oben. \
erforderlich oder führt die Umleitung wie bei jedem anderen Befehl aus. Bash-Erweiterung.expr a \< b > /dev/null
: POSIX-Äquivalent², siehe: https://stackoverflow.com/questions/21294867/how-to-test-strings-for-lexicographic-less-than-or-equal-in-bash/52707989#52707989&&
und ||
[[ a = a && b = b ]]
: wahr, logisch und[ a = a && b = b ]
: Syntaxfehler, der &&
als UND-Befehlstrennzeichen analysiert wirdcmd1 && cmd2
[ a = a -a b = b ]
: äquivalent, aber von POSIX³ veraltet[ a = a ] && [ b = b ]
: POSIX und zuverlässiges Äquivalent(
[[ (a = a || a = b) && a = b ]]
: falsch[ ( a = a ) ]
: Syntaxfehler, ()
wird als Subshell interpretiert[ \( a = a -o a = b \) -a a = b ]
: äquivalent, wird aber ()
von POSIX nicht mehr unterstützt{ [ a = a ] || [ a = b ]; } && [ a = b ]
POSIX-Äquivalent 5Wortteilung und Generierung von Dateinamen bei Erweiterungen (split + glob)
x='a b'; [[ $x = 'a b' ]]
: true, keine Anführungszeichen erforderlichx='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? ]]
: true, weil es Pattern Matching macht ( * ? [
sind magisch). Wird nicht global auf Dateien im aktuellen Verzeichnis erweitert.[ ab = a? ]
: a?
glob erweitert. Dies kann je nach den Dateien im aktuellen Verzeichnis wahr oder falsch sein.[ ab = a\? ]
: false, keine Glob-Erweiterung=
und ==
sind in beiden [
und gleich [[
, ist aber ==
eine Bash-Erweiterung.case ab in (a?) echo match; esac
: POSIX-Äquivalent[[ ab =~ 'ab?' ]]
: false 4 , verliert Magie mit''
[[ ab? =~ 'ab?' ]]
: wahr=~
[[ ab =~ ab? ]]
: true, POSIX- Übereinstimmung mit erweiterten regulären Ausdrücken , ?
Glob-Erweiterung nicht möglich[ a =~ a ]
: Syntax-Fehler. 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 : immer verwenden []
.
Für jedes [[ ]]
Konstrukt, das ich gesehen habe, gibt es POSIX-Entsprechungen .
Wenn Sie Sie benutzen [[ ]]
:
[
ist nur ein regulärer Befehl mit einem seltsamen Namen, es ist keine spezielle Semantik involviert.¹ Inspiriert von dem entsprechenden [[...]]
Konstrukt in der Korn-Shell
² schlägt jedoch für einige Werte von a
oder b
(wie +
oder index
) fehl und führt einen numerischen Vergleich durch, wenn a
und b
wie Dezimalzahlen aussehen. expr "x$a" '<' "x$b"
funktioniert um beide.
³ und fällt auch für einige Werte von a
oder b
wie !
oder aus (
.
4 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
)
5 obwohl die Gruppierung (hier mit der {...;}
Befehlsgruppe, statt der (...)
eine unnötige Subshell ausgeführt werden würde) nicht erforderlich ist, da die Operatoren ||
und die &&
Shell (im Gegensatz zu den Operatoren ||
und &&
[[...]]
oder den Operatoren -o
/ -a
[
) den gleichen Vorrang haben. Wäre [ a = a ] || [ a = b ] && [ a = b ]
also gleichwertig.
printf 'ab' | grep -Eq 'ab?'
innerhalb if [ … ]
?
if ( printf 'ab' | grep -Eq 'a' ); then echo 'a'; fi
. []
ist ein Befehl wie grep
. Das wird ()
für diesen Befehl möglicherweise nicht benötigt. Ich bin mir nicht sicher: Ich habe es hinzugefügt, da es davon |
abhängt, wie Bash die Dinge analysiert. Wenn es keine gäbe |
, kannst du sicher nur schreiben if cmd arg arg; then
.
()
scheint: stackoverflow.com/questions/8965509/…
Single Bracket dh []
ist POSIX - Shell konform einen bedingten Ausdruck zu umschließen.
Doppel Brackets dh [[]]
ist eine erweiterte (oder Erweiterung) Version von Standard - POSIX - Version, wird dies durch bash und andere Shells unterstützt wird (zsh, KSH).
In der bash für 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 integriert ist, wird ein neuer Prozess erstellt.[[
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
if
, ob