Soweit ich weiß, [[
handelt es sich um eine erweiterte Version von [
, aber ich bin verwirrt, wenn ich [[
als Schlüsselwort sehe und [
als eingebaut angezeigt werde.
[root@server ~]# type [
[ is a shell builtin
[root@server ~]# type [[
[[ is a shell keyword
TLDP sagt
Ein Builtin kann ein Synonym für einen Systembefehl mit demselben Namen sein, Bash implementiert ihn jedoch intern neu. Beispielsweise ist der Befehl "Bash echo" nicht mit "/ bin / echo" identisch, obwohl sein Verhalten nahezu identisch ist.
und
Ein Schlüsselwort ist ein reserviertes Wort, ein Token oder ein Operator. Schlüsselwörter haben eine besondere Bedeutung für die Shell und sind in der Tat die Bausteine der Shell-Syntax. Als Beispiele für, while, do und! sind Schlüsselwörter. Ähnlich wie ein eingebautes Schlüsselwort ist ein Schlüsselwort fest in Bash codiert, aber im Gegensatz zu einem eingebauten Schlüsselwort ist ein Schlüsselwort an sich kein Befehl, sondern eine Untereinheit eines Befehlskonstrukts. [2]
Sollte das nicht beides [
und [[
ein Schlüsselwort sein? Fehlt mir hier etwas? Außerdem bestätigt dieser Link , dass beide zur selben Art gehören [
und [[
gehören sollten.
quelle
if "[" $x -eq 3 ]
wie erwartet (weil Bash nach dem aufgerufenen Befehl sucht[
und dieser existiert),if "[[" $x -eq 3 ]]
funktioniert aber nicht (weil Bash erneut nach einem Befehl mit dem entsprechenden Namen sucht, aber es gibt keinen[[
Befehl)./usr/bin/echo
, aber das heißt nicht, dass es nicht eingebaut ist .Antworten:
Der Unterschied zwischen
[
und[[
ist sehr grundlegend.[
ist ein Befehl. Seine Argumente werden genauso verarbeitet wie alle anderen Befehlsargumente. Betrachten Sie zum Beispiel:Die Shell wird erweitert
$name
und führt sowohl die Wortteilung als auch die Dateinamengenerierung für das Ergebnis durch, genau wie für jeden anderen Befehl.Beispielsweise schlägt Folgendes fehl:
Damit dies korrekt funktioniert, sind Anführungszeichen erforderlich:
[[
ist ein Shell-Schlüsselwort und seine Argumente werden nach speziellen Regeln verarbeitet. Betrachten Sie zum Beispiel:Die Shell wird erweitert, führt
$name
jedoch im Gegensatz zu anderen Befehlen weder eine Wortteilung noch eine Dateinamengenerierung für das Ergebnis durch. Beispielsweise wird trotz der eingebetteten Leerzeichen Folgendes erfolgreich seinname
:Zusammenfassung
[
ist ein Befehl und unterliegt den gleichen Regeln wie alle anderen Befehle, die die Shell ausführt.Da
[[
es sich um ein Schlüsselwort und nicht um einen Befehl handelt, wird es von der Shell speziell behandelt und unter sehr unterschiedlichen Regeln ausgeführt.quelle
man bash
. Siehe insbesondere die Abschnitte "EINFACHE BEFEHLSERWEITERUNG" und "BEFEHLSAUSFÜHRUNG". Zusätzlich zu[[
, andere bash Schlüsselwörter enthaltenif
,then
,while
, und ‚Fall‘. Es gibt keine allgemeinen Regeln für Schlüsselwörter: Jedes Schlüsselwort ist ein Sonderfall.man bash
enthält Details für jeden.In V7 wurde Unix - wo die Bourne-Shell ihr Debüt gab -
[
aufgerufentest
und existierte nur als/bin/test
. Code, den Sie heute schreiben würden als:du hättest stattdessen geschrieben als
Diese zweite Notation existiert immer noch und ich finde, dass es klarer ist, was los ist: Sie rufen einen Befehl auf
test
, der seine Argumente auswertet und einen Exit-Statuscode zurückgibt , derif
verwendet, um zu entscheiden, was als nächstes zu tun ist. Dieser Befehl kann in die Shell eingebaut sein, oder es kann sich um ein externes Programm handeln.¹[
als Alternative zutest
später gekommen. Es kann ein eingebautes Synonym für seintest
, aber es wird auch wie/bin/[
auf modernen Systemen für Schalen bereitgestellt , die es nicht als eingebautes haben.[
undtest
kann unter Verwendung des gleichen Codes implementiert werden. Dies ist bei/bin/[
und/bin/test
unter OS X der Fall , bei denen es sich um feste Verknüpfungen zu derselben ausführbaren Datei handelt.³ Folglich ignoriert die Implementierung das nachfolgende Element vollständig]
: Es ist nicht erforderlich, wenn Sie es als aufrufen/bin/[
, und es beklagt sich nicht wenn Sie es bereitstellen/bin/test
.⁴Nichts davon hat Auswirkungen auf die Geschichte
[[
, da nie ein ursprüngliches Programm aufgerufen wurde[[
. Es existiert nur in den Shells, die es als Erweiterung der POSIX-Shell implementieren .Ein Teil der Unterscheidung zwischen "builtin" und "keyword" ist auf diese Historie zurückzuführen. Dies spiegelt auch die Tatsache wider, dass die Syntaxregeln für das Parsen von
[[
Ausdrücken unterschiedlich sind, wie in der Antwort von John1024 ausgeführtFußnoten:
Wenn Sie es so betrachten, wird deutlich, warum Sie
[
in Shell-Skripten Leerzeichen einfügen müssen, im Gegensatz zu der Art und Weise, wie Klammern und Klammern in den meisten anderen Programmiersprachen funktionieren. Wenn der Befehlsparser der Shellif["$x"...
dies zulässt, muss er dies auch zulasseniftest"$x"...
Es geschah um 1980.
/bin/[
In meiner Kopie von Ancient Unix V7 aus dem Jahr 1979 ist es weder vorhanden nochman test
als Alias dokumentiert. In dem entsprechenden Manpage Eintrag I in einer Pre-Release - Kopie des habe System III von 1980 Handbuch, es ist aufgeführt.ls -i /bin/[ /bin/test
Aber rechnen Sie nicht mit diesem Verhalten. Die in Bash integrierte Version von
[
erfordert das Schließen]
, und die integriertetest
Implementierung wird sich beschweren, wenn Sie sie bereitstellen.Die Unterscheidung zwischen integrierten und externen Befehlen kann auch aus einem anderen Grund von Bedeutung sein: Die beiden Implementierungen können sich unterschiedlich verhalten. Dies ist bei
echo
vielen Systemen der Fall . Da es nur eine Implementierung gibt, muss für ein Schlüsselwort keine solche Unterscheidung getroffen werden.quelle
builtin
undkeyword
Unterscheidung zwischen[
und[[
wenn beide bieten die gleiche Funktionalität ( mit Ausnahme der Tatsache , dass[[
mit mehr Funktionen kommt als[
)?[[
ist ein Schlüsselwort, mit dem bash Dinge erledigen kann, mit denen es nicht möglich ist.[
Beispielsweise ist das Zitieren nicht viel Zeit erforderlich, da die Shell weiß, dass es sich um eine Variable handelt. Das heißt, die Verarbeitung der Befehlszeile wird beeinflusst, wenn ein Schlüsselwort verwendet wird, nicht jedoch, wenn ein eingebautes Schlüsselwort verwendet wird - das geschieht viel später.[
Version enthält, der Code jedoch auskommentiert ist.cd
ist ein eingebautes, aber es spiegelt nichts (cd
kann nicht als externes Programm implementiert werden).[[
eines Schlüsselworts es der Shell ermöglicht, spezielle Parsing-Regeln für ihre Argumente zu verwenden. Leider geht meine Gegenstimme an John1024.[
war ursprünglich nur ein externer Befehl, ein anderer Name für/bin/test
. Einige Befehle wie[
undecho
werden jedoch in Shell-Skripten so häufig verwendet, dass die Shell-Implementierer beschlossen, den Code direkt in die Shell selbst zu kopieren, anstatt bei jeder Verwendung einen anderen Prozess ausführen zu müssen. Dadurch wurden diese Befehle zu "eingebauten" Befehlen, obwohl Sie das externe Programm weiterhin über seinen vollständigen Pfad aufrufen können.[[
kam viel später. Obwohl das Builtin intern in der Shell implementiert ist, wird es genau wie externe Befehle analysiert. Wie in John1024 Antwort erklärt, bedeutet dies , dass nicht notieren Variablen Wort Spaltung auf sie getan wird, und Token wie>
und<
als I / O - Umleitung verarbeitet. Dies machte das Schreiben komplexer Vergleichsausdrücke unbequem.[[
wurde als Shell-Syntax erstellt, damit sie ideosynkratisch analysiert werden kann. Innerhalb von[[
Variablen wird kein Wort getrennt<
und sie>
können als Vergleichsoperatoren=
verwendet werden. Je nachdem, ob der nächste Parameter in Anführungszeichen steht oder nicht , kann sich das Verhalten unterschiedlich verhalten. Dies sind alles Bequemlichkeiten, die[[
die Verwendung einfacher machen als beim herkömmlichen[
Befehl / Builtin.Sie konnten
[
die Syntax nicht einfach so umkodieren, da dies eine inkompatible Änderung an Millionen von Skripten gewesen wäre. Durch die Verwendung der neuen[[
Syntax, die es bisher nicht gab, konnte die Verwendung aufwärtskompatibel völlig überarbeitet werden.Dies ähnelt der Entwicklung, die zu einer
$((...))
Syntax für arithmetische Ausdrücke führte, die den traditionellenexpr
Befehl größtenteils ersetzt hat .quelle
Das neuere
[[
inbash
ist eine Optimierung von[
.Der Klassiker
[
hat einen großen Nachteil, wenn er häufig für einfache Operationen verwendet wird:Er erzeugt jedes Mal einen neuen Prozess: (Er erstellt einen neuen Adressraum nur zum Vergleichen
0
und1
! Jedes Mal!)Ich denke, ein Hauptaspekt des Hinzufügens von
[[
bestand darin, die Bewertung des Ausdrucks im Inneren[
nicht als zusätzlichen Prozess zu betrachten. Aber wie[
es funktioniert, könnte nicht geändert werden - es würde viel Verwirrung und Probleme verursachen. Daher wurde die Optimierung auf effizientere Weise unter einem neuen Namen implementiert, nämlich einem Shell-Builtin-Befehl.Als Nebeneffekt wurde es zum Schlüsselwort in der Shell-Syntax.
Zu der Zeit
[
wurde zunächst verwendet, es war der richtige Weg , dies mit einem externen Prozess zu tun.quelle
[
ursprünglich um einen externen Befehl handelte, dieser jedoch schon sehr früh als integrierter Bestandteil der Shell hinzugefügt wurde, wahrscheinlich zu der Zeit, als Unix System III und definitiv vor der Veröffentlichung von Unix System V. Der "Extra-Prozess" war also schon seit Ewigkeiten kein Problem mehr. Die Syntax blieb jedoch unverändert - es wurde so behandelt, als wäre es ein externer Befehl.[
das beides ist - das bedeutet einige Änderungen ...