Mehr als jede andere Sprache, die ich kenne, habe ich Bash jedes Mal durch Googeln "gelernt", wenn ich etwas brauche. Folglich kann ich kleine Skripte zusammenfügen, die anscheinend funktionieren. Allerdings glaube ich nicht wirklich wissen , was los ist , und ich hatte gehofft , für eine formelle Einführung in die Bash als Programmiersprache. Zum Beispiel: Wie lautet die Bewertungsreihenfolge? Was sind die Scoping-Regeln? Was ist die Schreibdisziplin, zB ist alles eine Zeichenfolge? Wie ist der Status des Programms? Ist es eine Schlüsselwertzuweisung von Zeichenfolgen zu Variablennamen? Gibt es mehr als das, zB den Stapel? Gibt es einen Haufen? Und so weiter.
Ich dachte, ich würde das GNU Bash-Handbuch für diese Art von Einsicht konsultieren, aber es scheint nicht das zu sein, was ich will. Es ist eher eine Wäscheliste mit syntaktischem Zucker als eine Erklärung des semantischen Kernmodells. Die millionenfachen "Bash-Tutorials" im Internet sind nur noch schlimmer. Vielleicht sollte ich zuerst sh
Bash als syntaktischen Zucker studieren und darüber hinaus verstehen? Ich weiß jedoch nicht, ob dies ein genaues Modell ist.
Irgendwelche Vorschläge?
EDIT: Ich wurde gebeten, Beispiele dafür zu liefern, wonach ich im Idealfall suche. Ein ziemlich extremes Beispiel für eine "formale Semantik" ist dieses Papier über "die Essenz von JavaScript" . Ein etwas weniger formelles Beispiel ist vielleicht der Haskell 2010-Bericht .
quelle
Antworten:
Eine Shell ist eine Schnittstelle für das Betriebssystem. Es ist normalerweise eine mehr oder weniger robuste Programmiersprache für sich, aber mit Funktionen, die es einfach machen, spezifisch mit dem Betriebssystem und dem Dateisystem zu interagieren. Die Semantik der POSIX-Shell (im Folgenden nur als "Shell" bezeichnet) ist ein bisschen wie ein Köter, der einige Funktionen von LISP (S-Ausdrücke haben viel mit der Aufteilung von Shell- Wörtern gemeinsam ) und C (ein Großteil der arithmetischen Syntax der Shell) kombiniert Semantik kommt von C).
Die andere Wurzel der Syntax der Shell liegt in ihrer Erziehung als Mischmasch einzelner UNIX-Dienstprogramme. Die meisten der häufig in der Shell integrierten Funktionen können tatsächlich als externe Befehle implementiert werden. Es wirft viele Shell-Neophyten für eine Schleife, wenn sie erkennen, dass dies
/bin/[
auf vielen Systemen vorhanden ist.wat?
Dies ist viel sinnvoller, wenn Sie sich ansehen, wie eine Shell implementiert ist. Hier ist eine Implementierung, die ich als Übung gemacht habe. Es ist in Python, aber ich hoffe, das ist für niemanden ein Auflegen. Es ist nicht besonders robust, aber lehrreich:
Ich hoffe, dass das Obige deutlich macht, dass das Ausführungsmodell einer Shell ziemlich genau ist:
Erweiterung, Befehlsauflösung, Ausführung. Die gesamte Semantik der Shell hängt mit einem dieser drei Dinge zusammen, obwohl sie weitaus umfangreicher sind als die Implementierung, die ich oben geschrieben habe.
Nicht alle Befehle
fork
. Tatsächlich gibt es eine Handvoll Befehle, die als extern nicht sinnvoll sinnvoll sind (so dass sie es müssten)fork
), aber selbst diese sind häufig als externe für die strikte POSIX-Konformität verfügbar.Bash baut auf dieser Basis auf und fügt neue Funktionen und Schlüsselwörter hinzu, um die POSIX-Shell zu verbessern. Es ist nahezu kompatibel mit sh und bash ist so allgegenwärtig, dass einige Skriptautoren Jahre damit verbringen, ohne zu bemerken, dass ein Skript möglicherweise nicht auf einem POSIX-strengen System funktioniert. (Ich frage mich auch, wie die Leute sich so sehr um die Semantik und den Stil einer Programmiersprache kümmern können und so wenig um die Semantik und den Stil der Shell, aber ich bin anderer Meinung.)
Reihenfolge der Bewertung
Dies ist eine Trickfrage: Bash interpretiert Ausdrücke in seiner primären Syntax von links nach rechts, aber in seiner arithmetischen Syntax folgt sie der C-Priorität. Ausdrücke unterscheiden sich jedoch von Erweiterungen . Aus dem
EXPANSION
Abschnitt des Bash-Handbuchs:Wenn Sie Wortsplitting, Pfadnamenerweiterung und Parametererweiterung verstehen, sind Sie auf dem besten Weg, die meisten Funktionen von Bash zu verstehen. Beachten Sie, dass die Pfadnamenerweiterung nach dem Aufteilen von Wörtern von entscheidender Bedeutung ist, da dadurch sichergestellt wird, dass eine Datei mit einem Leerzeichen im Namen weiterhin von einem Glob abgeglichen werden kann. Aus diesem Grund ist die gute Verwendung von Glob-Erweiterungen besser als das Parsen von Befehlen im Allgemeinen .
Umfang
Funktionsumfang
Ähnlich wie altes ECMAscript hat die Shell einen dynamischen Bereich, es sei denn, Sie deklarieren explizit Namen innerhalb einer Funktion.
Umwelt und Prozess "Umfang"
Subshells erben die Variablen ihrer übergeordneten Shells, andere Arten von Prozessen erben jedoch keine nicht exportierten Namen.
Sie können diese Bereichsregeln kombinieren:
Schreibdisziplin
Ähm, Typen. Ja. Bash hat wirklich keine Typen und alles wird zu einer Zeichenfolge erweitert (oder vielleicht wäre ein Wort besser geeignet). Aber lassen Sie uns die verschiedenen Arten von Erweiterungen untersuchen.
Saiten
So ziemlich alles kann als String behandelt werden. Barwörter in Bash sind Zeichenfolgen, deren Bedeutung vollständig von der darauf angewendeten Erweiterung abhängt.
Keine ErweiterungEs kann sich lohnen zu zeigen, dass ein bloßes Wort wirklich nur ein Wort ist und dass Zitate daran nichts ändern.
TeilstringerweiterungWeitere Informationen zu Erweiterungen finden Sie im
Parameter Expansion
Abschnitt des Handbuchs. Es ist ziemlich mächtig.Ganzzahlen und arithmetische Ausdrücke
Sie können Namen mit dem Integer-Attribut versehen, um die Shell anzuweisen, die rechte Seite von Zuweisungsausdrücken als arithmetisch zu behandeln. Wenn der Parameter dann erweitert wird, wird er als ganzzahlige Mathematik ausgewertet, bevor er zu… einem String erweitert wird.
Arrays
Argumente und PositionsparameterBevor Sie über Arrays sprechen, sollten Sie die Positionsparameter diskutieren. Die Argumente für ein Shell - Skript kann mit nummerierten Parameter, die zugegriffen werden soll
$1
,$2
,$3
, etc. Sie alle diese Parameter auf einmal zugreifen können"$@"
, die Erweiterung viele Dinge gemeinsam mit Arrays hat. Sie können die Positionsparameter mithilfe derset
oder integriertenshift
Funktionen oder einfach durch Aufrufen der Shell oder einer Shell-Funktion mit den folgenden Parametern festlegen und ändern :Das Bash-Handbuch wird manchmal auch
Arrays$0
als Positionsparameter bezeichnet. Ich finde das verwirrend, weil es es nicht in die Argumentanzahl einbezieht$#
, aber es ist ein nummerierter Parameter, also meh.$0
ist der Name der Shell oder des aktuellen Shell-Skripts.Die Syntax von Arrays wird nach Positionsparametern modelliert, daher ist es meistens sinnvoll, sich Arrays als benannte Art von "externen Positionsparametern" vorzustellen, wenn Sie möchten. Arrays können mit den folgenden Ansätzen deklariert werden:
Sie können über den Index auf Array-Elemente zugreifen:
Sie können Arrays in Scheiben schneiden:
Wenn Sie ein Array als normalen Parameter behandeln, erhalten Sie den nullten Index.
Wenn Sie Anführungszeichen oder Backslashes verwenden, um das Aufteilen von Wörtern zu verhindern, behält das Array das angegebene Aufteilen von Wörtern bei:
Der Hauptunterschied zwischen Arrays und Positionsparametern ist:
$12
eingestellt ist, können Sie sicher sein, dass auch$11
eingestellt ist. (Es könnte auf die leere Zeichenfolge gesetzt werden, wird aber$#
nicht kleiner als 12 sein.) Wenn"${arr[12]}"
gesetzt ist, gibt es keine Garantie,"${arr[11]}"
die gesetzt ist, und die Länge des Arrays könnte so klein wie 1 sein.shift
einem Array müssen Sie es in Scheiben schneiden und neu zuweisen, wie zarr=( "${arr[@]:1}" )
. Sie könnten es auch tununset arr[0]
, aber das würde das erste Element bei Index 1 ergeben.Es ist oft praktisch, Pfadnamenerweiterungen zu verwenden, um Arrays von Dateinamen zu erstellen:
Befehle
Befehle sind der Schlüssel, aber sie werden auch ausführlicher behandelt, als ich es im Handbuch kann. Lesen Sie den
SHELL GRAMMAR
Abschnitt. Die verschiedenen Arten von Befehlen sind:$ startx
)$ yes | make config
) (lol)$ grep -qF foo file && sed 's/foo/bar/' file > newfile
)$ ( cd -P /var/www/webroot && echo "webroot is $PWD" )
)Ausführungsmodell
Das Ausführungsmodell umfasst natürlich sowohl einen Heap als auch einen Stack. Dies ist in allen UNIX-Programmen endemisch. Bash hat auch einen Aufrufstapel für Shell-Funktionen, der über die verschachtelte Verwendung von sichtbar ist
caller
Systems .Verweise:
SHELL GRAMMAR
Abschnitt des Bash-HandbuchsBitte machen Sie Kommentare, wenn Sie möchten, dass ich in eine bestimmte Richtung weiter expandiere.
quelle
yes | make config
;-) Aber im Ernst, eine sehr gute Zusammenfassung./bin/[
und/bin/test
ist oft die gleiche Anwendung. 2) "Angenommen, das erste Wort ist ein Befehl." - Erwarten Sie, wenn Sie Aufgabe tun ...execle
und die ersten Wörter in die Umgebung interpolieren, aber das würde es noch ein bisschen komplizierter machen.a = 1
nicht arbeiten).Die Antwort auf Ihre Frage "Was ist die Schreibdisziplin, z. B. ist alles eine Zeichenfolge?" Bash-Variablen sind Zeichenfolgen. Bash erlaubt jedoch arithmetische Operationen und Vergleiche von Variablen, wenn Variablen Ganzzahlen sind. Die Ausnahme für Regel-Bash-Variablen sind Zeichenfolgen, wenn diese Variablen gesetzt oder anderweitig deklariert sind
Optionsbedeutungen deklarieren:
quelle
Die Bash-Manpage enthält viel mehr Informationen als die meisten Manpages und enthält einige der gewünschten Informationen. Nach mehr als einem Jahrzehnt Scripting Bash gehe ich davon aus, dass es aufgrund seiner Geschichte als Erweiterung von sh eine funky Syntax hat (um die Abwärtskompatibilität mit sh aufrechtzuerhalten).
FWIW, meine Erfahrung war wie deine; Obwohl die verschiedenen Bücher (z. B. O'Reilly "Learning the Bash Shell" und ähnliches) bei der Syntax helfen, gibt es viele seltsame Möglichkeiten, verschiedene Probleme zu lösen, und einige davon sind nicht im Buch enthalten und müssen gegoogelt werden.
quelle