Eine Shell ist der Befehlsinterpreter des Betriebssystems. Bash ist meine Lieblingsshell, aber jede Linux-Shell interpretiert die vom Benutzer oder Systemadministrator eingegebenen Befehle in eine Form, die das Betriebssystem verwenden kann. Wenn die Ergebnisse an das Shell-Programm zurückgegeben werden, sendet es sie an STDOUT, das sie standardmäßig im Terminal anzeigt. Alle mir bekannten Shells sind auch Programmiersprachen.

Funktionen wie die Tabulatorvervollständigung, das Aufrufen und Bearbeiten von Befehlszeilen und Abkürzungen wie Aliase tragen alle zu ihrem Wert als leistungsfähige Shell bei. Der Standard-Befehlszeilen-Editiermodus verwendet Emacs, aber eine meiner Lieblingsfunktionen der Bash ist, dass ich in den Vi-Modus wechseln kann, um Editierbefehle zu verwenden, die bereits Teil meines Muskelgedächtnisses sind.

Wenn man die Bash jedoch nur als Shell betrachtet, verpasst man viel von ihrer wahren Stärke. Bei der Recherche für meinen dreibändigen Linux-Selbstlernkurs (auf dem diese Artikelserie basiert) habe ich Dinge über die Bash gelernt, die ich in über 20 Jahren Arbeit mit Linux noch nie gewusst habe. Einige dieser neuen Erkenntnisse beziehen sich auf ihre Verwendung als Programmiersprache. Bash ist eine leistungsstarke Programmiersprache, die perfekt für die Verwendung auf der Kommandozeile und in Shell-Skripten geeignet ist.

In dieser dreiteiligen Serie wird die Verwendung von Bash als Programmiersprache für die Befehlszeilenschnittstelle (CLI) untersucht. Dieser erste Artikel befasst sich mit einfacher Befehlszeilenprogrammierung mit Bash, Variablen und Steueroperatoren. Die weiteren Artikel befassen sich mit Bash-Dateitypen, String-, numerischen und verschiedenen logischen Operatoren, die eine Logik zur Steuerung des Ausführungsflusses bieten, mit verschiedenen Arten von Shell-Erweiterungen sowie mit den for-, while- und until-Schleifen, die wiederholte Operationen ermöglichen. Sie werden sich auch einige Befehle ansehen, die die Verwendung dieser Werkzeuge vereinfachen und unterstützen.

Die Shell

Eine Shell ist der Befehlsinterpreter des Betriebssystems. Bash ist meine Lieblingsshell, aber jede Linux-Shell interpretiert die vom Benutzer oder Systemadministrator eingegebenen Befehle in eine Form, die das Betriebssystem verwenden kann. Wenn die Ergebnisse an das Shell-Programm zurückgegeben werden, zeigt es sie im Terminal an. Alle mir bekannten Shells sind auch Programmiersprachen.

Bash steht für Bourne Again Shell, weil die Bash-Shell auf der älteren Bourne-Shell basiert, die 1977 von Steven Bourne geschrieben wurde. Es gibt noch viele andere Shells, aber dies sind die vier, die mir am häufigsten begegnen:

  • csh: Die C-Shell für Programmierer, die die Syntax der Sprache C mögen
  • ksh: Die Korn-Shell, geschrieben von David Korn und beliebt bei Unix-Benutzern
  • tcsh: Eine Version von csh mit mehr benutzerfreundlichen Funktionen
  • zsh: Die Z-Shell, die viele Funktionen anderer beliebter Shells kombiniert

Alle Shells haben eingebaute Befehle, die die von den Kerndienstprogrammen bereitgestellten ergänzen oder ersetzen. Öffnen Sie die Manpage der Shell und suchen Sie den Abschnitt „BUILT-INS“, um zu sehen, welche Befehle sie bereitstellt.

Jede Shell hat ihre eigene Persönlichkeit und Syntax. Einige werden für Sie besser funktionieren als andere. Ich habe die C-Shell, die Korn-Shell und die Z-Shell benutzt. Die Bash-Shell gefällt mir immer noch besser als alle anderen. Verwenden Sie diejenige, die für Sie am besten funktioniert, auch wenn Sie dafür vielleicht einige der anderen ausprobieren müssen. Glücklicherweise ist es recht einfach, die Shells zu wechseln.

Alle diese Shells sind Programmiersprachen und Befehlsinterpreter. Hier ist ein kurzer Überblick über einige Programmierkonstrukte und Werkzeuge, die integraler Bestandteil der Bash sind.

Bash als Programmiersprache

Die meisten Systemadministratoren haben die Bash benutzt, um Befehle einzugeben, die in der Regel recht einfach und unkompliziert sind. Aber Bash kann mehr als nur einzelne Befehle eingeben, und viele Sysadmins erstellen einfache Befehlszeilenprogramme, um eine Reihe von Aufgaben auszuführen. Diese Programme sind gängige Werkzeuge, die Zeit und Mühe sparen können.

Mein Ziel beim Schreiben von CLI-Programmen ist es, Zeit und Mühe zu sparen (d.h. der faule Sysadmin zu sein). CLI-Programme unterstützen dies, indem sie mehrere Befehle in einer bestimmten Reihenfolge auflisten, die nacheinander ausgeführt werden, so dass Sie nicht den Fortschritt eines Befehls beobachten und den nächsten Befehl eingeben müssen, wenn der erste beendet ist. Sie können sich anderen Dingen widmen und müssen nicht ständig den Fortschritt der einzelnen Befehle überwachen.

Was ist ein „Programm“?

Das Free On-line Dictionary of Computing (FOLDOC) definiert ein Programm als: „Die Anweisungen, die von einem Computer ausgeführt werden, im Gegensatz zu dem physischen Gerät, auf dem sie laufen.“ Das WordNet der Princeton University definiert ein Programm als: „…eine Folge von Anweisungen, die ein Computer interpretieren und ausführen kann…“. Wikipedia hat auch einen guten Eintrag über Computerprogramme.

Ein Programm kann demnach aus einer oder mehreren Anweisungen bestehen, die eine bestimmte, verwandte Aufgabe ausführen. Eine Anweisung eines Computerprogramms wird auch als Programmanweisung bezeichnet. Für Sysadmins ist ein Programm in der Regel eine Folge von Shell-Befehlen. Alle für Linux verfügbaren Shells, zumindest die, mit denen ich vertraut bin, verfügen zumindest über eine grundlegende Form der Programmierfähigkeit, und die Bash, die Standard-Shell der meisten Linux-Distributionen, bildet da keine Ausnahme.

In dieser Serie wird zwar die Bash verwendet (weil sie so allgegenwärtig ist), aber wenn Sie eine andere Shell verwenden, sind die allgemeinen Programmierkonzepte die gleichen, auch wenn sich die Konstrukte und die Syntax etwas unterscheiden können. Einige Shells unterstützen vielleicht einige Funktionen, die andere nicht haben, aber sie bieten alle einige Programmiermöglichkeiten. Shell-Programme können zur wiederholten Verwendung in einer Datei gespeichert oder nach Bedarf auf der Befehlszeile erstellt werden.

Einfache CLI-Programme

Die einfachsten Befehlszeilenprogramme sind eine oder zwei aufeinanderfolgende Programmanweisungen, die miteinander in Beziehung stehen können oder auch nicht, die auf der Befehlszeile eingegeben werden, bevor die Eingabetaste gedrückt wird. Die zweite Anweisung in einem Programm, wenn es eine gibt, kann von den Aktionen der ersten abhängig sein, muss es aber nicht.

Es gibt auch eine kleine syntaktische Interpunktion, die deutlich gemacht werden muss. Bei der Eingabe eines einzelnen Befehls in der Befehlszeile wird der Befehl durch Drücken der Eingabetaste mit einem impliziten Semikolon (;) abgeschlossen. Bei der Verwendung in einem CLI-Shell-Programm, das als einzelne Zeile in die Befehlszeile eingegeben wird, muss das Semikolon jede Anweisung beenden und sie von der nächsten trennen. Die letzte Anweisung in einem CLI-Shell-Programm kann ein explizites oder implizites Semikolon verwenden.

Einige grundlegende Syntax

Die folgenden Beispiele sollen diese Syntax verdeutlichen. Dieses Programm besteht aus einem einzigen Befehl mit einem expliziten Terminator:

$ echo "Hello world." ;
Hello world.

Das mag nicht nach einem großen Programm aussehen, aber es ist das erste Programm, das mir bei jeder neuen Programmiersprache begegnet, die ich lerne. Die Syntax mag für jede Sprache ein wenig anders sein, aber das Ergebnis ist dasselbe.

Lassen Sie uns dieses triviale, aber allgegenwärtige Programm ein wenig näher betrachten. Ihre Ergebnisse werden sich von meinen unterscheiden, weil ich andere Experimente durchgeführt habe, während Sie vielleicht nur die Standardverzeichnisse und -dateien haben, die im Home-Verzeichnis des Kontos erstellt werden, wenn Sie sich zum ersten Mal über die grafische Benutzeroberfläche in ein Konto einloggen.

$ echo "My home directory." ; ls ;
My home directory.
chapter25 TestFile1.Linux dmesg2.txt Downloads newfile.txt softlink1 testdir6
chapter26 TestFile1.mac dmesg3.txt file005 Pictures Templates testdir
TestFile1 Desktop dmesg.txt link3 Public testdir Videos
TestFile1.dos dmesg1.txt Documents Music random.txt testdir1

Das macht ein bisschen mehr Sinn. Die Ergebnisse sind miteinander verbunden, aber die einzelnen Programmanweisungen sind unabhängig voneinander. Beachten Sie, dass ich gerne Leerzeichen vor und nach dem Semikolon einfüge, weil der Code dann etwas leichter zu lesen ist. Versuchen Sie das kleine CLI-Programm noch einmal ohne explizites Semikolon am Ende:

$ echo "My home directory." ; ls 

Es gibt keinen Unterschied in der Ausgabe.

Etwas über Variablen

Wie alle Programmiersprachen kann auch die Bash-Shell mit Variablen umgehen. Eine Variable ist ein symbolischer Name, der sich auf eine bestimmte Stelle im Speicher bezieht, die einen Wert enthält. Der Wert einer Variable ist veränderbar, d.h. er ist variabel.

Die Bash typisiert Variablen nicht wie C und verwandte Sprachen, indem sie sie als Integer-, Fließkomma- oder Stringtypen definiert. In Bash sind alle Variablen Zeichenketten. Eine Zeichenkette, die eine ganze Zahl ist, kann in der Ganzzahlarithmetik verwendet werden, der einzigen Art von Mathematik, die die Bash beherrscht. Wenn komplexere Mathematik erforderlich ist, kann der bc-Befehl in CLI-Programmen und Skripten verwendet werden.

Variablen werden Werte zugewiesen und können verwendet werden, um auf diese Werte in CLI-Programmen und Skripten zu verweisen. Der Wert einer Variable wird mit ihrem Namen, aber ohne vorangestelltes $-Zeichen gesetzt. Die Zuweisung VAR=10 setzt den Wert der Variable VAR auf 10. Um den Wert der Variable zu drucken, können Sie die Anweisung echo $VAR verwenden. Beginnen Sie mit Textvariablen (d.h. nicht numerischen Variablen).

Bash-Variablen werden Teil der Shell-Umgebung, bis sie aufgehoben werden.

Prüfen Sie den Anfangswert einer nicht zugewiesenen Variablen; er sollte Null sein. Weisen Sie der Variablen dann einen Wert zu und drucken Sie ihn aus, um seinen Wert zu überprüfen. Sie können all dies in einem einzigen CLI-Programm durchführen:

$ echo $MyVar ; MyVar="Hello World" ; echo $MyVar ;
Hello World
$

Hinweis: Die Syntax der Variablenzuweisung ist sehr streng. Es dürfen keine Leerzeichen auf beiden Seiten des Gleichheitszeichens (=) in der Zuweisungsanweisung vorhanden sein.

Die leere Zeile zeigt an, dass der Anfangswert von MyVar null ist. Das Ändern und Setzen des Wertes einer Variablen erfolgt auf die gleiche Weise. In diesem Beispiel werden sowohl der ursprüngliche als auch der neue Wert angezeigt.

Wie bereits erwähnt, kann die Bash ganzzahlige arithmetische Berechnungen durchführen, was für die Berechnung eines Verweises auf die Position eines Elements in einem Array oder die Lösung einfacher mathematischer Probleme nützlich ist. Sie eignet sich nicht für wissenschaftliche Berechnungen oder für alles, was Dezimalzahlen erfordert, wie z.B. finanzielle Berechnungen. Für diese Art von Berechnungen gibt es viel bessere Werkzeuge.

Hier ist eine einfache Berechnung:

$ Var1="7" ; Var2="9" ; echo "Result = $((Var1*Var2))"
Result = 63

Was passiert, wenn Sie eine mathematische Operation durchführen, die eine Gleitkommazahl ergibt?

Das Ergebnis ist die nächste Ganzzahl. Beachten Sie, dass die Berechnung als Teil der echo-Anweisung durchgeführt wurde. Die Mathematik wird aufgrund der Bash-Reihenfolge vor dem einschließenden echo-Befehl ausgeführt.

Kontrolloperatoren

Shell-Kontrolloperatoren gehören zu den syntaktischen Operatoren, mit denen sich auf einfache Weise interessante Befehlszeilenprogramme erstellen lassen. Die einfachste Form eines CLI-Programms ist die Aneinanderreihung mehrerer Befehle in der Befehlszeile:

command1 ; command2 ; command3 ; command4 ; . . . ; etc. ;

Diese Befehle laufen alle problemlos, solange keine Fehler auftreten. Aber was passiert, wenn ein Fehler auftritt? Mit den eingebauten Bash-Kontrolloperatoren && und || können Sie Fehler vorhersehen und berücksichtigen. Diese beiden Kontrolloperatoren bieten eine gewisse Flusskontrolle und ermöglichen es Ihnen, die Reihenfolge der Codeausführung zu ändern. Das Semikolon gilt ebenfalls als Bash-Kontrolloperator, ebenso wie das Newline-Zeichen.

Der &&-Operator sagt einfach: „Wenn Befehl1 erfolgreich ist, dann führe Befehl2 aus. Wenn Befehl1 aus irgendeinem Grund fehlschlägt, dann wird Befehl2 übersprungen.“ Diese Syntax sieht folgendermaßen aus:

command1 && command2

Schauen wir uns nun einige Befehle an, mit denen ein neues Verzeichnis erstellt und – falls erfolgreich – zum aktuellen Arbeitsverzeichnis (PWD) gemacht wird. Stellen Sie sicher, dass Ihr Heimatverzeichnis (~) das PWD ist. Versuchen Sie dies zuerst in /root, einem Verzeichnis, auf das Sie keinen Zugriff haben:

Der Fehler wurde durch den Befehl mkdir ausgelöst. Sie haben keinen Fehler erhalten, der angibt, dass die Datei nicht erstellt werden konnte, weil die Erstellung des Verzeichnisses fehlgeschlagen ist. Der &&-Kontrolloperator erkannte den Rückgabewert ungleich Null, so dass der Befehl touch übersprungen wurde. Die Verwendung des Steueroperators && verhindert, dass der Touch-Befehl ausgeführt wird, weil bei der Erstellung des Verzeichnisses ein Fehler auftrat. Diese Art der Ablaufsteuerung von Befehlszeilenprogrammen kann verhindern, dass sich Fehler häufen und ein echtes Chaos verursachen. Aber es ist an der Zeit, ein wenig komplizierter zu werden.

Mit dem Steueroperator || können Sie eine weitere Programmanweisung hinzufügen, die ausgeführt wird, wenn die erste Programmanweisung einen Code größer als Null zurückgibt. Die grundlegende Syntax sieht wie folgt aus:

command1 || command2 

Diese Syntax lautet: „Wenn Befehl1 fehlschlägt, führe Befehl2 aus.“ Das bedeutet, dass Befehl2 übersprungen wird, wenn Befehl1 erfolgreich ist. Versuchen Sie dies, indem Sie versuchen, ein neues Verzeichnis zu erstellen:

Das ist genau das, was Sie erwarten würden. Da das neue Verzeichnis nicht erstellt werden konnte, schlug der erste Befehl fehl, was zur Ausführung des zweiten Befehls führte.

Die Kombination dieser beiden Operatoren bietet das Beste von beiden. Die Syntax des Kontrolloperators, der eine gewisse Flusskontrolle verwendet, nimmt diese allgemeine Form an, wenn die Kontrolloperatoren && und || verwendet werden:

preceding commands ; command1 && command2 || command3 ; following commands

Diese Syntax kann wie folgt angegeben werden: „Wenn Befehl1 mit einem Rückgabewert von 0 beendet wird, dann führe Befehl2 aus, ansonsten führe Befehl3 aus.“ Versuchen Sie es:

Nun versuchen Sie den letzten Befehl noch einmal, indem Sie Ihr Home-Verzeichnis anstelle des /root-Verzeichnisses verwenden. Sie werden die Erlaubnis haben, dieses Verzeichnis zu erstellen:

$ Dir=~/testdir ; mkdir $Dir && cd $Dir || echo "$Dir was not created."
$

Die Syntax des Steueroperators, wie Befehl1 && Befehl2, funktioniert, weil jeder Befehl einen Rückgabewert (RC) an die Shell sendet, der angibt, ob er erfolgreich ausgeführt wurde oder ob während der Ausführung ein Fehler auftrat. Konventionell bedeutet ein RC von Null (0) Erfolg, und jede positive Zahl bedeutet eine Art von Fehler. Einige der Werkzeuge, die Sysadmins verwenden, geben nur eine Eins (1) zurück, um einen Fehler anzuzeigen, aber viele verwenden andere Codes, um die Art des aufgetretenen Fehlers anzuzeigen.

Die Bash-Shell-Variable $? enthält die RC des letzten Befehls. Dieser RC kann sehr einfach durch ein Skript, den nächsten Befehl in einer Liste von Befehlen oder sogar direkt durch den Sysadmin überprüft werden. Beginnen Sie damit, einen einfachen Befehl auszuführen und sofort die RC zu überprüfen. Der RC-Wert bezieht sich immer auf den letzten Befehl, der ausgeführt wurde, bevor Sie ihn sich angesehen haben.

Der RC-Wert ist in diesem Fall Null, was bedeutet, dass der Befehl erfolgreich abgeschlossen wurde. Versuchen Sie nun, denselben Befehl im Home-Verzeichnis von root auszuführen, einem Verzeichnis, für das Sie keine Berechtigungen haben:

In diesem Fall ist der RC-Wert zwei; das bedeutet, dass einem Nicht-Root-Benutzer der Zugriff auf ein Verzeichnis verweigert wurde, auf das der Benutzer keinen Zugriff hat. Die Kontrolloperatoren verwenden diese RCs, um die Reihenfolge der Programmausführung zu ändern.

Zusammenfassung

In diesem Artikel wurde die Bash als Programmiersprache betrachtet und ihre grundlegende Syntax sowie einige grundlegende Werkzeuge untersucht. Es wurde gezeigt, wie man Daten auf STDOUT ausgibt und wie man Variablen und Steuerungsoperatoren verwendet. Der nächste Artikel in dieser Reihe befasst sich mit einigen der vielen logischen Operatoren der Bash, die den Ablauf der Befehlsausführung steuern.

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht.