# 1.103.1

# Arbeiten auf der Kommandozeile

Beschreibung: Prüfungskandidaten sollten in der Lage sein, mit Shell und Kommandos auf der Kommandozeile umzugehen. Das beinhaltet das Schreiben gültiger Kommandos und Kommandoabfolgen, das Definieren, Referenzieren und Exportieren von Umgebungsvariablen, die Benutzung der Kommando-History und Eingabemöglichkeiten, das Aufrufen von Kommandos im und außerhalb des Suchpfades, das Benutzen von Kommandosubstitution, das rekursive Anwenden von Kommandos über einen Verzeichnisbaum und das Verwenden von man, um Informationen über Kommandos zu erhalten.

Die wichtigsten Dateien, Bezeichnungen und Anwendungen:

- .
- bash
- echo
- env
- exec
- export
- man
- pwd
- set
- unset
- `~/.bash_history`
- `~/.profile`

### Kommandos

An dieser Stelle werden noch nicht viele Kommandos vorausgesetzt. Trotzdem sollten grundlegende Befehle wie `less, more, cat, echo, ...` klar sein und problemlos verwendet werden können.

Grundsätzlich ist ein Unix-Kommando immer gleich aufgebaut. Zuerst wird das Programm angegeben, dann optionale Parameter und dann die Dateien, auf die das Programm angewandt werden soll.

Parameter liegen meist in zwei verschiedenen Formen vor, einmal als kurze Form, eingeleitet durch einen Bindestrich gefolgt von einem Buchstaben (wie etwa `-r`) und andererseits als lange Form, eingeleitet durch zwei Bindestriche gefolgt von einem Wort (`--recursive`). Kurze Parameter können dabei meist zusammengefasst werden, so daß statt `-z -v -f` einfach `-zvf` geschrieben werden kann. Das erklärt auch, warum lange Parameter mit zwei Bindestrichen beginnen. Sonst könnte ja ein `--recursive` als `-r -e -c -u -r -s -i -v -e` missinterpretiert werden.

### Kommandoeingabe

Grundsätzlich ist die Eingabe von Kommandos eine Eingabe an die Shell (bash). Die Shell interpretiert das eingegebene Kommando, ersetzt bestimmte Muster durch Dateinamen oder Variableninhalte und führt erst dann das Kommando aus.

Linux-Kommandos werden entweder einfach eingegeben, oder zusammen mit dem Pfad, der die genaue Position des aufzurufenden Programmes im Dateisystem festlegt. Normalerweise reicht der Aufruf eines Kommandos ohne Pfad, wenn das Kommando im Suchpfad liegt.

Der Suchpfad wird in einer Shellvariable `PATH` definiert, die in der Regel in den Konfigurationsdateien der Shell mit vernünftigen Werten belegt wird. Diese Variable enthält eine durch Doppelpunkte getrennte Liste von Verzeichnissen, die von der Shell nach einem Befehl durchsucht werden sollen. Das aktuelle Verzeichnis ist nicht automatisch Teil des Suchpfades (wie bei DOS/Windows) sondern wird nur durchsucht, wenn es explizit durch die Angabe eines einzelnen Punktes im Suchpfad angegeben wurde.

Welches Verzeichnis gerade das aktuelle Arbeitsverzeichnis ist, kann mit dem Befehl pwd herausgefunden werden. Dieser Befehl gibt den kompletten absoluten Pfad des aktuellen Arbeitsverzeichnisses auf der Standard-Ausgabe aus.

Die Shell durchsucht den Suchpfad in der angegebenen Reihenfolge. Existieren auf einem System jetzt zwei Programme gleichen Namens, so wird das Programm ausgeführt, das sich in dem zuerst im Suchpfad genannten Verzeichnis befindet. Dieser Mechanismus kann umgangen werden, wenn nicht nur der Programmname, sondern der komplette Pfad als Befehl eingegeben wird. Auch Programme, die sich in Verzeichnissen befinden, die nicht im Suchpfad sind, können auf diese Weise aufgerufen werden.

Die Eingabe gültiger Kommandos und Kommandogruppen beinhaltet natürlich auch das Wissen um die verschiedenen Möglichkeiten, mehrere Befehle in eine Befehlszeile zu schreiben. Zur Erinnerung sind hier nochmal die verschiedenen Möglichkeiten der bash aufgelistet:

`Kommando1 ; Kommando2`
  Kommando2 wird nach Kommando1 ausgeführt.
`Kommando1 & Kommando2`
  Kommando1 und Kommando2 werden gleichzeitig ausgeführt (K1 im Hintergrund, K2 im Vordergrund)
`Kommando1 && Kommando2`
  Kommando2 wird nur dann ausgeführt, wenn Kommando1 fehlerfrei abgeschlossen wurde (Rückgabewert 0)
`Kommando1 || Kommando2`
  Kommando2 wird nur dann ausgeführt, wenn Kommando1 nicht fehlerfrei abgeschlossen wurde (Rückgabewert ungleich 0)

Wenn ein Kommando durch die Enter-Taste abgeschlossen wurde, dann wird es ausgeführt, sofern es syntaktisch fertig war. Fehlt aber noch etwas, für den syntaktischen Abschluß, war also etwa ein Anführungszeichen, das noch nicht durch ein zweites abgeschlossen wurde, so erscheint ein Folgeprompt, der eine weitere Eingabe ermöglicht. Das wird solange fortgesetzt, bis die Eingabe syntaktisch vollständig ist.

Vor der eigentlichen Ausführung des Kommandos wird der gesamte eingegebene Befehl in einen Kommandospeicher abgespeichert, aus dem er jederzeit (durch Navigieren mit den Pfeiltasten nach oben und unten) wiedergeholt und erneut ausgeführt werden kann. Wird die Shell beendet (etwa durch das Ausloggen), so werden alle im Kommandospeicher gespeicherten Befehle in die Datei `~/.bash_history` im Heimatverzeichnis des jeweiligen Users abgelegt, so daß die Befehle auch beim erneuten Einloggen wieder zur Verfügung stehen.

Ein eingegebenes Kommando erzeugt in der Regel einen neuen Prozeß. Wenn der Prozeß abgeschlossen wurde kehrt die Shell wieder zur Eingabeaufforderung zurück. Ein spezieller Befehl erlaubt es aber, einen Befehl einzugeben, der die Shell ersetzt. Der Befehl exec Kommando ersetzt den Shellprozeß durch den Prozeß des eingegebenen Kommandos. Das macht Sinn, wenn eine andere Shell aufgerufen werden soll oder der Befehl innerhalb eines Scripts ausgeführt wird. Wird ein durch exec ausgeführter Befehl beendet, ist aber logischerweise die Shell nicht mehr da, der Shellprozeß wurde ja durch das Kommando ersetzt.

### Umgebungsvariablen

Variablen sind kleine Stücke des Arbeitsspeichers - genauer gesagt des Umgebungsspeichers der jeweiligen Shell - die einen Namen haben und einen Wert speichern können. Jede Instanz einer Shell hat einen eigenen Umgebungsspeicher, so daß verschiedene Shell-Instanzen gleichnamige Variablen mit unterschiedlichen Werten besitzen können.

Umgebungsvariablen werden in einer Shell definiert, indem sie einfach mit der Anweisung

Variablenname=Wert

angelegt werden. Existierte die Variable mit dem entsprechenden Namen noch nicht, so wird sie neu angelegt, gab es sie schon, so wird ihr Wert verändert.

Um auf den Inhalt (Wert) einer Variable zuzugreifen (refernzieren der Variable), wird dem Variablennamen ein Dollarzeichen ($) vorangestellt. Wenn die Shell auf ein Dollarzeichen stößt, versucht sie, den darauf folgenden Begriff als Variablennamen zu interpretieren und das ganze Konstrukt mit dem Wert der entsprechenden Variable zu ersetzen.

      NAME=Huber
      VORNAME=Hans
      echo Hallo $VORNAME $NAME

        Hallo Hans Huber

Alle definierten Variablen sind mit dem Befehl set anzeigbar, mit unset können Variablen aus dem Umgebungsspeicher entfernt werden:

      unset NAME
      unset VORNAME

Wenn aus einer Shell heraus eine neue Shell (Subshell) aufgerufen wird, dann werden nicht automatisch alle Variablen der aufrufenden Shell für die Subshell übernommen. Um eine bestimmte Variable an spätere Subshells weiterzugeben, muß diese Variable exportiert werden. Das geschieht mit der Shell-Anweisung `export`. Dabei kann entweder eine bestehende Variable exportiert werden wie mit

`export Variablenname`

oder eine Variable gleich so definiert werden, daß sie später exportiert wird mit

`export Variablenname=Wert`

Eine exportierte Variable ist eine Kopie der Orginalvariablen. Das heißt, daß die Orginalvariable der aufrufenden Shell unverändert bleibt, wenn die exportierte Variable der Subshell verändert wird!

Variablen, die immer wieder benötigt werden, können in der Datei `~/.profile` im Homeverzeichnis jedes Users definiert werden. Diese Datei wird bei jedem Start einer Login-Shell abgearbeitet. So stehen einmal dort definierte Variablen jederzeit wieder zur Verfügung.

Soll ein Kommando mit bestimmten Variablen zusammen aufgerufen werden (also in einer bestimmten Umgebung), dann kann das mit dem Befehl env erledigt werden. Dabei kann entweder das Programm in einer völlig leeren Umgebung gestartet werden, oder zusätzliche Variablen werden speziell für diesen Programmaufruf definiert.

### Kommandosubstitution

Bei der Kommandosubstitution handelt es sich um ein Konstrukt, das eine Subshell öffnet, einen bestimmten Teil einer Kommandozeile in dieser Subshell ausführt und das, was diese Ausführung auf die Standard-Ausgabe schreiben würde, an die Stelle der ursprünglichen Kommandozeile einfügt, an der das Substitutionskonstrukt stand. Erst jetzt wird die gesamte Zeile ausgeführt.

Es gibt zwei Möglichkeiten, die Kommandosubstitution einzuschalten. Zum einen die Klammerung mit dem Grave-Zeichen (```) und zum anderen das Konstrukt `$(...)`

Das klingt schlimmer als es ist, ein einfaches Beispiel soll zeigen, worum es geht:

Der Befehl `pwd` gibt an, in welchem Verzeichnis wir uns gerade befinden (Print WorkingDirectory). Wir werden ihn jetzt in einer Kommandosubstitution benutzen. Das Kommando

      echo Wir befinden uns im Verzeichnis $(pwd)

wird eingegeben. Statt dessen wäre auch

      echo Wir befinden uns im Verzeichnis `pwd`

gegangen. Was passiert nun mit dieser Befehlszeile? Die Shell ließt diese Zeile und stößt auf das Konstrukt `$(pwd)`. Sie erkennt dieses Konstrukt als Aufruf einer Kommandosubstitution und startet jetzt eine Subshell. Diese Subshell führt den Befehl `pwd` aus. Dieser Befehl schreibt das aktuelle Arbeitsverzeichnis auf die Standard-Ausgabe. Nehmen wir mal an, wir befänden uns im Verzeichnis `/home/hans`. Die Ausgabe des Befehls wäre also `/home/hans`. Jetzt ersetzt die ursprüngliche Shell das Konstrukt `$(pwd)` mit der Ausgabe der Subshell, also mit `/home/hans`. Die dadurch entstehende Kommandozeile lautet jetzt also

      echo Wir befinden uns im Verzeichnis /home/hans

Und erst jetzt führt die Shell dieses Kommando aus.

### Rekursives Anwenden von Kommandos

Viele Unix Kommandos erlauben es, daß sie nicht nur auf eine Datei oder ein Verzeichnis angewandt werden können, sondern auf ganze Verzeichnis-Hierarchien. Dazu steht meist ein Kommandozeilen-Parameter wie -r, -R oder --recursive zur Verfügung. Unglücklicherweise unterscheiden sich die Kommandos dabei ob -r oder -R verstanden wird. Der lange Parameter --recursive funktioniert aber überall, wo Rekursion überhaupt zur Verfügung steht. Ein paar Beispiele:

Befehl | Kurze Form | Lange Form
--- | --- | ---
`ls` | `-R` | `--recursive`
`chown` | `-R` | `--recursive`
`chmod` | `-R` | `--recursive`
`chgrp` | `-R` | `--recursive`
`grep` | `-r` | `--recursive`
`cp` | `-r` und `-R` | `--recursive`
`rm` | `-r` und `-R` | `--recursive`

### Informationen über Befehle mit man

Bei der Vielzahl von Linux-Befehlen, kann es sehr schnell passieren, daß man vergisst, welche Parameter von welchem Programm verstanden werden. Linux bietet eine Online-Hilfe an, die diese Informationen bereitstellt. Dabei handelt es sich um ein komplettes Handbuchsystem, das sowohl ausgedruckt, als auch auf dem Bildschirm dargestellt werden kann.

In der Vorbereitung auf die LPI102 Prüfung wird dieses Handbuchsystem noch genauer erläutert. Für den einfachen Umgang damit reichen die folgenden Informationen:

Das Programm man bietet Zugriff auf die Handbuchseiten (manual-pages). Es erwartet mindestens den Namen des Programmes als Parameter, über das Informationen dargestellt werden sollen. Um also Informationen über den Befehl cp (copy) zu erhalten, genügt der Befehl

      man cp

Das Programm man stellt jetzt eine Handbuchseite zum Thema cp zusammen und gibt sie über den systemeigenen Pager (meist das Programm less auf dem Bildschirm aus.