Ein wichtiger Teil des Erlernens der Arbeit mit Ubuntu und Linux-Distributionen im Allgemeinen ist das Erlernen der Arbeit in der Shell-Umgebung. Während die grafischen Desktop-Umgebungen wie GNOME, die in Linux enthalten sind, eine benutzerfreundliche Oberfläche für das Betriebssystem bieten, bietet die Shell-Umgebung in der Praxis weitaus mehr Möglichkeiten, Flexibilität und Automatisierung, als mit grafischen Desktop-Tools jemals erreicht werden kann. Die Shell-Umgebung bietet auch eine Möglichkeit, mit dem Betriebssystem zu interagieren, wenn keine Desktop-Umgebung zur Verfügung steht, was häufig vorkommt, wenn man mit einem serverbasierten Betriebssystem wie Ubuntu oder einem beschädigten System arbeitet, das nicht vollständig hochgefahren werden kann.

Das Ziel dieses Kapitels ist es daher, einen Überblick über die Standard-Shell-Umgebung von Ubuntu (insbesondere die Bash-Shell) zu geben.

1.1 Was ist eine Shell?

Die Shell ist eine interaktive Befehlsinterpretationsumgebung, in der Befehle an einer Eingabeaufforderung eingegeben oder in Form eines Skripts in eine Datei eingegeben und ausgeführt werden können. Die Ursprünge der Shell lassen sich bis in die Anfangszeit des UNIX-Betriebssystems zurückverfolgen. In der Tat war die Shell in den Anfängen von Linux vor der Einführung von grafischen Desktops die einzige Möglichkeit für einen Benutzer, mit dem Betriebssystem zu interagieren.

Im Laufe der Jahre wurden verschiedene Shell-Umgebungen entwickelt. Die erste weit verbreitete Shell war die Bourne-Shell, die von Stephen Bourne in den Bell Labs geschrieben wurde.

Eine weitere frühe Kreation war die C-Shell, die einige syntaktische Ähnlichkeiten mit der Programmiersprache C aufwies und Verbesserungen der Benutzerfreundlichkeit wie Befehlszeilenbearbeitung und Historie einführte.

Die Korn-Shell (entwickelt von David Korn in den Bell Labs) basiert auf Funktionen der Bourne-Shell und der C-Shell.

Die Standard-Shell von Ubuntu ist die Bash-Shell (Abkürzung für Bourne Again SHell). Diese Shell, die als Open-Source-Version der Bourne-Shell entstand, wurde von Brian Fox für das GNU-Projekt entwickelt und basiert auf Funktionen der Bourne-Shell und der C-Shell.

1.2 Zugriff auf die Shell

Aus der GNOME-Desktop-Umgebung heraus kann die Shell-Eingabeaufforderung von einem Terminal-Fenster aus aufgerufen werden, indem man die Option Aktivitäten in der oberen Leiste auswählt, Terminal in die Suchleiste eingibt und auf das Terminal-Symbol klickt.

Beim Fernzugriff auf einen Ubuntu-Server, zum Beispiel über SSH, wird dem Benutzer ebenfalls eine Shell-Eingabeaufforderung angezeigt. Details zum Zugriff auf einen entfernten Server über SSH werden im Kapitel „Konfigurieren der SSH-Schlüssel-basierten Authentifizierung unter Ubuntu“ behandelt. Beim Booten eines serverbasierten Systems, auf dem keine Desktop-Umgebung installiert wurde, wird die Shell sofort aufgerufen, nachdem der Benutzer die Anmeldeprozedur am physischen Konsolenterminal oder an der Remote-Anmeldesitzung abgeschlossen hat.

1.3 Eingabe von Befehlen an der Eingabeaufforderung

Befehle werden an der Shell-Eingabeaufforderung eingegeben, indem der Befehl einfach eingegeben und die Eingabetaste gedrückt wird. Während einige Befehle Aufgaben im Stillen ausführen, zeigen die meisten eine Art von Ausgabe an, bevor sie zur Eingabeaufforderung zurückkehren. Der Befehl ls kann beispielsweise verwendet werden, um die Dateien und Verzeichnisse im aktuellen Arbeitsverzeichnis anzuzeigen:

$ ls

Desktop Dokumente Downloads Musik Bilder Öffentliche Vorlagen Videos

Die verfügbaren Befehle sind entweder in der Shell selbst integriert oder befinden sich im physischen Dateisystem. Der Speicherort eines Befehls im Dateisystem kann mit dem Befehl which ermittelt werden. Um zum Beispiel herauszufinden, wo sich der ausführbare Befehl ls im Dateisystem befindet:

$ which ls alias ls='ls --color=auto' /usr/bin/ls

Der Befehl ls befindet sich eindeutig im Verzeichnis /usr/bin. Beachten Sie auch, dass ein Alias konfiguriert ist, ein Thema, das später in diesem Kapitel behandelt wird. Wenn Sie den Befehl which verwenden, um den Pfad zu Befehlen zu finden, die in die Shell integriert sind, erhalten Sie eine Meldung, dass die ausführbare Datei nicht gefunden werden kann. Wenn Sie zum Beispiel versuchen, den Ort des history-Befehls zu finden (der eigentlich in die Shell eingebaut ist und nicht als ausführbare Datei im Dateisystem existiert), erhalten Sie eine Ausgabe ähnlich der folgenden:

$ which history/usr/bin/which: no history in (/home/demo/.local/bin:/home/demo/bin:/usr/share/Modules/bin:/usr/local/bin:/usr/bin:/usr/local/sbin:/usr/sbin)

1.4 Informationen über einen Befehl erhalten

Viele der Befehle, die der Linux-Shell zur Verfügung stehen, können anfangs kryptisch erscheinen. Um detaillierte Informationen darüber zu erhalten, was ein Befehl tut und wie er zu verwenden ist, verwenden Sie den Befehl man, wobei Sie den Namen des Befehls als Argument angeben. Um zum Beispiel mehr über den Befehl pwd zu erfahren:

$ man pwd

Wenn der obige Befehl ausgeführt wird, wird eine detaillierte Beschreibung des Befehls pwd angezeigt. Viele Befehle liefern auch zusätzliche Informationen, wenn sie mit der Befehlszeilenoption -help ausgeführt werden:

$ wc --help

1.5 Bash-Befehlszeilenbearbeitung

Frühe Shell-Umgebungen boten keine Möglichkeit zur Zeilenbearbeitung. Das bedeutete, dass man, wenn man einen Fehler am Anfang einer langen Befehlszeile entdeckte, alle folgenden Zeichen löschen, den Fehler korrigieren und dann den Rest des Befehls neu eingeben musste. Glücklicherweise bietet die Bash eine breite Palette von Optionen zur Bearbeitung von Befehlszeilen, wie in der folgenden Tabelle dargestellt:

Tastenfolge Aktion
Strg-b oder Pfeil links Cursor eine Position zurückbewegen
Strg-f oder Pfeil rechts Cursor eine Position vorwärts bewegen
Löschen Löschen des Zeichens unter dem Cursor
Rückschritt Löschen des Zeichens links vom Cursor
Strg-_ Vorherige Änderung rückgängig machen (kann wiederholt werden, um alle vorherigen Änderungen rückgängig zu machen)
Strg-a Cursor an den Anfang der Zeile bewegen
Strg-e Cursor an das Ende der Zeile bewegen
Meta-f oder Esc dann f Cursor ein Wort vorwärts bewegen
Meta-b oder Esc dann b Cursor ein Wort zurück bewegen
Strg-l Löschen des Bildschirms von allem außer dem aktuellen Befehl
Strg-k Löschen bis zum Ende der Zeile ab der aktuellen Cursorposition
Meta-d oder Esc dann d Löschen bis zum Ende des aktuellen Wortes
Meta-DEL oder Esc dann DEL Löschen bis zum Anfang des aktuellen Wortes
Ctrl-w Löschen von der aktuellen Cursorposition bis zum vorherigen Leerzeichen

Tabelle 9-1

1.6 Arbeiten mit der Shell-Historie

Zusätzlich zu den Funktionen zum Bearbeiten der Befehlszeile bietet die Bash-Shell auch eine Unterstützung für die Befehlszeilen-Historie. Eine Liste der zuvor ausgeführten Befehle kann mit dem History-Befehl eingesehen werden:

$ history1ps2ls3ls –l /4ls5man pwd6man apropos

Zusätzlich können Strg-p (oder Pfeil nach oben) und Strg-n (oder Pfeil nach unten) verwendet werden, um durch die zuvor eingegebenen Befehle vor- und zurückzublättern. Wenn der gewünschte Befehl aus der Historie angezeigt wird, drücken Sie die Eingabetaste, um ihn auszuführen.

Eine weitere Möglichkeit ist die Eingabe des Zeichens ‚!‘, gefolgt von den ersten Zeichen des zu wiederholenden Befehls, gefolgt von der Eingabetaste.

1.7 Dateinamenkurzschrift

Viele Shell-Befehle benötigen einen oder mehrere Dateinamen als Argumente. Um beispielsweise den Inhalt einer Textdatei mit dem Namen list.txt anzuzeigen, wird der Befehl cat wie folgt verwendet:

$ cat list.txt

Auch der Inhalt mehrerer Textdateien kann angezeigt werden, indem man alle Dateinamen als Argumente angibt:

$ cat list.txt list2.txt list3.txt list4.txt

Anstatt jeden einzelnen Namen einzugeben, kann man mit dem Mustervergleich alle Dateien angeben, deren Namen bestimmten Kriterien entsprechen. So kann das obige Beispiel durch das Platzhalterzeichen ‚*‘ vereinfacht werden:

$ cat *.txt

Der obige Befehl zeigt den Inhalt aller Dateien an, die mit der Erweiterung .txt enden. Dies kann weiter eingeschränkt werden auf alle Dateinamen, die mit list beginnen und auf .txt enden:

$ cat list*.txt

Einzelne Zeichenübereinstimmungen können mit dem ‚?‘-Zeichen angegeben werden:

$ cat list?.txt

1.8 Vervollständigung von Dateinamen und Pfaden

Anstatt einen ganzen Dateinamen oder Pfad einzugeben oder Mustervergleiche zu verwenden, um die Menge der Eingabe zu reduzieren, bietet die Shell die Funktion der Vervollständigung von Dateinamen. Um die Dateinamensvervollständigung zu nutzen, geben Sie einfach die ersten Zeichen des Datei- oder Pfadnamens ein und drücken Sie dann zweimal die Esc-Taste. Die Shell vervollständigt dann den Dateinamen für Sie mit dem ersten Datei- oder Pfadnamen im Verzeichnis, der mit den von Ihnen eingegebenen Zeichen übereinstimmt. Um eine Liste möglicher Übereinstimmungen zu erhalten, drücken Sie Esc = nach Eingabe der ersten Zeichen.

1.9 Eingabe- und Ausgabeumleitung

Wie bereits erwähnt, geben viele Shell-Befehle bei ihrer Ausführung Informationen aus. Standardmäßig geht diese Ausgabe in eine Gerätedatei namens stdout, die im Wesentlichen das Terminalfenster oder die Konsole ist, in der die Shell läuft. Umgekehrt nimmt die Shell Eingaben von einer Gerätedatei namens stdin entgegen, bei der es sich standardmäßig um die Tastatur handelt.

Die Ausgabe eines Befehls kann mit dem Zeichen ‚>‘ von stdout in eine physische Datei im Dateisystem umgeleitet werden. Um beispielsweise die Ausgabe eines ls-Befehls in eine Datei mit dem Namen files.txt umzuleiten, ist folgender Befehl erforderlich:

$ ls *.txt > files.txt

Die Datei files.txt enthält dann die Liste der Dateien im aktuellen Verzeichnis. In ähnlicher Weise kann der Inhalt einer Datei anstelle von stdin in einen Befehl eingegeben werden. Beispiel: Um den Inhalt einer Datei als Eingabe für einen Befehl umzuleiten:

$ wc –l < files.txt

Der obige Befehl zeigt die Anzahl der in der Datei files.txt enthaltenen Zeilen an.

Es ist wichtig zu beachten, dass der Umleitungsoperator „>“ eine neue Datei erstellt oder eine bestehende Datei abschneidet, wenn er verwendet wird. Um an eine bestehende Datei anzuhängen, verwenden Sie den ‚>>‘-Operator:

$ ls *.dat >> files.txt

Zusätzlich zur Standardausgabe bietet die Shell auch eine Standardfehlerausgabe mit stderr. Während die Ausgabe eines Befehls nach stdout geleitet wird, werden alle Fehlermeldungen, die der Befehl erzeugt, nach stderr geleitet. Das bedeutet, dass Fehlermeldungen auch dann im Terminal erscheinen, wenn stdout in eine Datei geleitet wird. Dies ist im Allgemeinen das gewünschte Verhalten, obwohl stderr auch mit dem Operator ‚2>‘ umgeleitet werden kann:

$ ls dkjfnvkjdnf 2> errormsg

Bei Beendigung des Befehls wird eine Fehlermeldung, dass die Datei mit dem Namen dkjfnvkjdnf nicht gefunden werden konnte, in der Datei errormsg enthalten sein.

Sowohl stderr als auch stdout können mit dem &>-Operator in dieselbe Datei umgeleitet werden:

$ ls /etc dkjfnvkjdnf &amp;&gt; alloutput

Nach Beendigung der Ausführung enthält die alloutput-Datei sowohl eine Auflistung des Inhalts des /etc-Verzeichnisses als auch die Fehlermeldung, die mit dem Versuch, eine nicht existierende Datei aufzulisten, verbunden ist.

1.10 Arbeiten mit Pipes in der Bash-Shell

Zusätzlich zur E/A-Umleitung erlaubt die Shell auch die direkte Weiterleitung der Ausgabe eines Befehls als Eingabe in einen anderen Befehl. Eine Pipe-Operation wird erreicht, indem das Zeichen „|“ zwischen zwei oder mehr Befehle in einer Befehlszeile gesetzt wird. Um beispielsweise die Anzahl der auf einem System laufenden Prozesse zu zählen, kann die Ausgabe des ps-Befehls über die Pipeline an den wc-Befehl weitergeleitet werden:

$ ps –ef | wc –l

Es gibt keine Begrenzung für die Anzahl der Pipe-Operationen, die in einer Befehlszeile ausgeführt werden können. Um zum Beispiel die Anzahl der Zeilen in einer Datei zu finden, die den Namen Smith enthalten:

$ cat namesfile | grep Smith | wc –l

1.11 Aliase konfigurieren

Wenn Sie sich mit der Shell-Umgebung vertraut machen, werden Sie wahrscheinlich häufig Befehle mit denselben Argumenten eingeben. Sie werden zum Beispiel oft den Befehl ls mit den Optionen l und t verwenden:

$ ls –lt

Um den Tippaufwand für einen Befehl zu verringern, können Sie einen Alias erstellen, der dem Befehl und den Argumenten entspricht. Um zum Beispiel einen Alias zu erstellen, so dass die Eingabe des Buchstabens l die Ausführung des Befehls ls -lt bewirkt, würde die folgende Anweisung verwendet:

$ alias l="ls –lt"

Die Eingabe von l an der Eingabeaufforderung führt nun die ursprüngliche Anweisung aus.

1.12 Umgebungsvariablen

Shell-Umgebungsvariablen dienen der temporären Speicherung von Daten und Konfigurationseinstellungen. Die Shell selbst richtet eine Reihe von Umgebungsvariablen ein, die vom Benutzer geändert werden können, um das Verhalten der Shell zu modifizieren. Eine Liste der derzeit definierten Variablen kann mit dem env-Befehl abgerufen werden:

$ envSSH_CONNECTION=192.168.0.19 61231 192.168.0.28 22MODULES_RUN_QUARANTINE=LD_LIBRARY_PATHLANG=en_US.UTF-8HISTCONTROL=ignoredupsHOSTNAME=demo-pc.ebookfrenzy.comXDG_SESSION_ID=15MODULES_CMD=/usr/share/Modules/libexec/modulecmd.tclUSER=demoENV=/usr/share/Modules/init/profile.shSELINUX_ROLE_REQUESTED=PWD=/home/demoHOME=/home/demoSSH_CLIENT=192.168.0.19 61231 22SELINUX_LEVEL_REQUESTED= ...

Die vielleicht nützlichste Umgebungsvariable ist PATH. Sie definiert die Verzeichnisse, in denen die Shell nach Befehlen sucht, die an der Eingabeaufforderung eingegeben werden, und die Reihenfolge, in der sie dies tut. Die Umgebungsvariable PATH für ein Benutzerkonto auf einem neu installierten Ubuntu-System wird wahrscheinlich wie folgt konfiguriert sein:

$ echo $PATH/home/demo/.local/bin:/home/demo/bin:/usr/share/Modules/bin:/usr/local/bin:/usr/ bin:/usr/local/sbin:/usr/sbin

Eine weitere nützliche Variable ist HOME, die das Heimatverzeichnis des aktuellen Benutzers angibt. Wenn Sie z.B. möchten, dass die Shell auch nach Befehlen im Verzeichnis scripts in Ihrem Heimatverzeichnis sucht, würden Sie die PATH-Variable wie folgt ändern:

$ export PATH=$PATH:$HOME/scripts

Der aktuelle Wert einer bestehenden Umgebungsvariable kann mit dem echo-Befehl angezeigt werden:

$ echo $PATH

Sie können Ihre eigenen Umgebungsvariablen mit dem export-Befehl erstellen. Beispiel:

$ export DATAPATH=/data/files

Ein nützlicher Trick, um die Ausgabe eines Befehls einer Umgebungsvariablen zuzuweisen, ist die Verwendung von Anführungszeichen (`) um den Befehl herum. Um zum Beispiel das aktuelle Datum und die Uhrzeit einer Umgebungsvariablen namens NOW zuzuweisen:

$ export NOW=`date`$ echo $NOWTue Apr 2 13:48:40 EDT 2020

Wenn es Umgebungsvariablen oder Alias-Einstellungen gibt, die Sie jedes Mal konfigurieren müssen, wenn Sie die Shell-Umgebung aufrufen, können Sie diese zu einer Datei in Ihrem Heimatverzeichnis namens .bashrc hinzufügen. Die folgende .bashrc-Datei ist zum Beispiel so konfiguriert, dass sie die Umgebungsvariable DATAPATH und einen Alias einrichtet:

# .bashrc # Source global definitionsif ; then . /etc/bashrcfi # User specific environmentPATH="$HOME/.local/bin:$HOME/bin:$PATH"export PATH # Uncomment the following line if you don't like systemctl's auto-paging feature:# export SYSTEMD_PAGER= # User specific aliases and functionsexport DATAPATH=/data/filesalias l="ls -lt"

1.13 Schreiben von Shell-Skripten

Bislang haben wir uns ausschließlich auf die interaktive Natur der Bash-Shell konzentriert. Mit interaktiv meinen wir die manuelle Eingabe von Befehlen an der Eingabeaufforderung, die nacheinander ausgeführt werden. Tatsächlich ist dies nur ein kleiner Teil dessen, was die Shell leisten kann. Einer der mächtigsten Aspekte der Shell ist wohl die Möglichkeit, Shell-Skripte zu erstellen. Shell-Skripte sind im Wesentlichen Textdateien, die Sequenzen von Anweisungen enthalten, die innerhalb der Shell-Umgebung ausgeführt werden können, um Aufgaben zu erfüllen. Neben der Möglichkeit, Befehle auszuführen, bietet die Shell viele der Programmierkonstrukte wie for- und do-Schleifen und if-Anweisungen, die man in einer Skriptsprache erwarten kann.

Leider würde ein detaillierter Überblick über Shell-Skripte den Rahmen dieses Kapitels sprengen. Es gibt jedoch viele Bücher und Web-Ressourcen, die sich dem Shell-Scripting widmen und dem Thema viel mehr gerecht werden, als wir es hier je könnten. In diesem Abschnitt werden wir daher nur einen kleinen Vorgeschmack auf die Shell-Skripterstellung geben.

Der erste Schritt bei der Erstellung eines Shell-Skripts besteht darin, eine Datei zu erstellen (für die Zwecke dieses Beispiels werden wir sie simple.sh) und als erste Zeile folgendes hinzuzufügen:

#!/bin/sh

Das #! wird als „shebang“ bezeichnet und ist eine spezielle Zeichenfolge, die angibt, dass der Pfad zum Interpreter, der für die Ausführung des Skripts benötigt wird, das nächste Element in der Zeile ist (in diesem Fall die ausführbare Datei sh, die sich in /bin befindet). Dies könnte z.B. auch /bin/csh oder /bin/ksh sein, wenn Sie einen der beiden Interpreter verwenden wollen.

Der nächste Schritt besteht darin, ein einfaches Skript zu schreiben:

#!/bin/shfor i in *do echo $idone

Alles, was dieses Skript tut, ist, durch alle Dateien im aktuellen Verzeichnis zu gehen und den Namen jeder Datei anzuzeigen. Das Skript kann ausgeführt werden, indem der Name des Skripts als Argument an sh übergeben wird:

$ sh simple.sh

Um die Datei ausführbar zu machen (wodurch die Notwendigkeit, sie an den sh-Befehl zu übergeben, entfällt), kann der chmod-Befehl verwendet werden:

$ chmod +x simple.sh

Wenn das Ausführungs-Bit in den Berechtigungen der Datei gesetzt wurde, kann sie direkt ausgeführt werden. Zum Beispiel:

$ ./simple.sh

1.14 Zusammenfassung

In diesem Kapitel der Ubuntu Essentials haben wir einen kurzen Rundgang durch die Bash-Shell-Umgebung gemacht. In der Welt der grafischen Desktop-Umgebungen vergisst man leicht, dass man die wahre Leistung und Flexibilität eines Betriebssystems oft nur dann nutzen kann, wenn man sich unter die benutzerfreundliche Desktop-Oberfläche begibt und eine Shell-Umgebung verwendet. Darüber hinaus ist die Vertrautheit mit der Shell eine Notwendigkeit, wenn es darum geht, serverbasierte Systeme zu verwalten und zu warten, auf denen der Desktop nicht installiert ist, oder wenn versucht wird, ein System zu reparieren, das so beschädigt ist, dass der Desktop oder die Cockpit-Oberfläche nicht mehr gestartet werden kann.

Schreibe einen Kommentar

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