\documentclass[a4paper,10pt]{article}
\usepackage[utf8]{inputenc}
\usepackage{ngerman}
%\usepackage{hyperref}
%\usepackage{graphicx}
\usepackage{geometry}
\geometry{a4paper, left=25mm, top=10mm}
\title{Workstation Linuxkurs}
\author{Paul Hänsch}

\begin{document}
\maketitle

\section{Tag 4}

\subsection{Arbeit mit der Shell}
Wir haben bisher einige Befehle kennen gelernt, um mit Dateien umzugehen. Von unserer Kommandozeile aus haben wir externe Programme, wie z.B. '\verb#touch#', '\verb#ls#' und '\verb#chmod#' aufgerufen. Das komplexeste Programm, das wir dabei benutzt haben, war allerdings die Kommandozeilenumgebung selbst.\\

Die Befehlszeile wird auch als ``Shell'' (Schale) bezeichnet, da sie gewissermaßen das Betriebssystem umschließt, und dem Benutzer präsentiert. Um die Arbeit der Shell zu verstehen müssen wir uns unsere bisherigen Befehlsaufrufe genauer angucken:\\
\verb#ls -l -h /home/user#\\

Hier wird ein Programm aufgerufen, und es werden Parameter übergeben:\\

\begin{tabular}{l|r|r|l}
\textbf{Programmname} & \textbf{Parameter 1} & \textbf{Parameter 2} & \textbf{Parameter 3} \\
\hline
\verb#ls# & \verb#-l# & \verb#-h# & \verb#/home/user# \\
\end{tabular}\\

Die Shell ist dafür verantwortlich, das eingegebene Kommando anhand der Leerzeichen zu zerlegen, die Programmdatei aufzufinden, auszuführen und dabei die Parameter einzeln zu übergeben. Wie wir sehen handelt es sich bei Parameter 3 um eine Pfadangabe. Für die Shell ist dies zunächst egal (auch wenn sie uns z.T. besondere Unterstützung bei der Eingabe von Pfaden bietet). Die Shell übergibt 3 Parameter an das Programm, wie das Programm (in diesem fall '\verb#ls#') diese Parameter interpretiert ist nicht mehr Sache der Shell.\\

Bei Parameter 1 ('-l') und Parameter 2 ('-h') handelt es sich offensichtlich nicht um Pfadangaben. Dies sind \textbf{Optionen} für das Programm. Auch hier ist die Interpretation der Optionen Sache des Programms. Die Shell übergibt die Parameter nur. Nehmen wir an, wir hätten beim Aufruf von '\verb#ls#' die Kurzform für die Optionen verwendet:\\
\verb#ls -lh /home/user#\\

Die Shell hätte das Programm auf folgende Weise aufgerufen:\\

\begin{tabular}{l|r|l}
\textbf{Programmname} & \textbf{Parameter 1} & \textbf{Parameter 2} \\
\hline
\verb#ls# & \verb#-lh# & \verb#/home/user# \\
\end{tabular}\\

Wir sehen wieder, dass nun beide Optionen als ein Parameter übergeben werden: das Programm ist dafür verantwortlich die Bedeutung dieser verkürzten Optionskette zu erkennen. Nicht jedes Programm ist dazu in der Lage, Parameter in dieser Kurzzform zu erkennen. Generell ist das Identifizieren von Optionen (z.B. anhand eines vorangehenden Bindestrichs) Sache des Programms.\\

Ein noch komplexeres Beispiel für die Arbeit der Shell ist das am Tag 1 ausgeführte '\verb#echo#':\\
\verb#echo Hallo Welt > datei1#\\

\begin{tabular}{l|r|r|r|r}
\textbf{Programmname} & \textbf{Parameter 1} & \textbf{Parameter 2} & \textbf{Shellumleitung} & \textbf{Umleitungsziel}\\
\hline
\verb#echo# & \verb#Hallo# & \verb#Welt# & \verb#># & \verb#datei1#
\end{tabular}\\

Zwei Dinge sind hier interssant:
\begin{enumerate}
  \item Die Shell betrachtet die Worte '\verb#Hallo Welt#' als zwei unterschiedliche Parameter da sie ja durch ein Leerzeichen getrennt sind.
  \item Die Umleitung der Ausgabe in die Datei 'datei1' wird von der \textbf{Shell} ausgeführt, \textbf{nicht vom Programm 'echo'}. Tatsächlich erfährt das Programm '\verb#echo#' zu keinem Zeitpunkt, dass diese Umleitung überhaupt stattfindet. Der Umleitungspfeil und das Umleitungsziel werden \textbf{nicht} als Parameter an das Programm übergeben.
\end{enumerate}

\textbf{Diese zweite Aussage ist besonders wichtig} und wir werden gleich nochmal darauf zurückkommen. Zunächst aber nochmal zur 1. Aussage: ``Hallo'' und ``Welt'' sind zwei verschiedene Parameter. Für die Shell ist es dabei egal, wie viele Leerzeichen vor, zwischen oder nach den Parametern stehen (sie muss die Worte nur unterscheiden können). Was passiert dann aber, wenn wir z.B. ``\verb#Hallo          Welt#'' (mit 10 Leerzeichen) ausgeben wollen?\\
\verb#echo Hallo          Welt#\\

\begin{tabular}{l|r|r}
\textbf{Programmname} & \textbf{Parameter 1} & \textbf{Parameter 2}\\
\hline
\verb#echo# & \verb#Hallo# & \verb#Welt#\\
\end{tabular}\\

Ausgabe $\Rightarrow$\\
\verb#Hallo Welt#\\

Das Programm erfährt nie, dass diese Leerzeichen existieren. Bei beiden Aufrufvarianten wurde an '\verb#echo#' nie ein Leerzeichen übergeben (aus Sicht von '\verb#echo#' waren die beiden letzten Aufrufe sogar identisch). Das Programm hat nur deswegen ein Leerzeichen mit ausgegeben, weil es sich ``denken'' konnte (bzw. weil sich sein Entwickler denken konnte), dass zwischen den beiden Parametern bei der Eingabe ein Leerzeichen stehen musste. Wie übergeben wir die Leerzeichen mit?\\
\verb#echo 'Hallo          Welt'#\\

\begin{tabular}{l|r}
\textbf{Programmname} & \textbf{Parameter 1}\\
\hline
\verb#echo# & \verb#Hallo          Welt#\\
\end{tabular}\\

Ausgabe $\Rightarrow$\\
\verb#Hallo          Welt#\\

\begin{itemize}
  \item Wir haben die Zeichenkette hier bei der Befehlseingabe in einfache Anführungsstriche eingeschlossen.
  \item Das Programm '\verb#echo#' erhält nur einen einzigen Parameter
  \item Der Parameter enthält \textbf{genau das}, was in den Anführungszeichen eingeschlossen ist, dies kann sogar Zeilenumbrüche mit einschließen ($\rightarrow$ Ausprobieren)
  \item Die Anführungszeichen selbst sind \textbf{nicht} Teil des übergeben Parameters!
\end{itemize}

Aus diesem letzten Punkt entsteht übrigens wieder ein Problem: was, wenn wir die Zeichenkette ``\verb#'Hallo Welt'#'' (mit Anführungszeichen) ausgeben wollen?\\
\verb#echo \'Hallo Welt\'#\\

\begin{tabular}{l|r|r}
\textbf{Programmname} & \textbf{Parameter 1} & \textbf{Parameter 2}\\
\hline
\verb#echo# & \verb#'Hallo# & \verb#Welt'#\\
\end{tabular}\\

Ausgabe $\Rightarrow$\\
\verb#'Hallo Welt'#\\

Wir haben jedem Anführungszeichen einfach einen Rückschrägstrich (Backslash) vorangestellt. Ein Backslash macht der Shell klar, dass sie das jeweils nachfolgende Zeichen nicht selbst interpretieren, sondern einfach ans Programm ``durchreichen'' soll. Man bezeichnet den Backslash in dieser Funktion als ``Escapecharacter'' oder deutsch ``Fluchtzeichen'' (umgangssprachlich oft ``Escapezeichen'') da ein Zeichen damit der Interpretation durch die Shell ``entflieht''. das Fluchtzeichen selbst wirrd nicht ans Programm ubergeben. Wenn wir einen Backslash selbst übergeben wollen, ``escapen'' wir diesen übrigens einfach auch mit einem Backslash:\\
\verb#echo \\#\\
$\Rightarrow$\\
\verb#\#\\

\subsection{Shellumleitungen}
Wir erwähnten vorher die Shellumleitung in Form eines Pfeils. Für uns sind zunächst zwei Arten von Shellumleitungen interessant:
\begin{itemize}
  \item die Umleitung von Programmausgaben in eine Datei (\verb#># und \verb#>>#)
  \item die Umleitung von Programmausgaben an ein weiteres Programm (\verb#|#)
\end{itemize}

\subsubsection{Ausgabeumleitung in Dateien}

Die Umleitung in eine Datei ist uns bereits bekannt. Wir haben sie wiederholt beim Aufruf von '\verb#echo#' durchgeführt.\\
\verb#echo Hallo Welt > datei1#\\

Da die Umleitung von der Shell ausgeführt wird, ist sie vollkommen Unabhängig vom Programm. Wir können damit also die Ausgabe von jedem beliebigen Programm in eine Datei leiten:\\
\verb#ls > datei1#\\
\verb#cat datei1#\\
$\Rightarrow$\\
... (Verzeichnisauflistung)\\

Angenommen, wir tun folgendes:\\
\verb#ls > datei1#\\
\verb#echo Hallo Welt > datei1#\\
\verb#cat datei1#\\
$\Rightarrow$\\
\verb#Hallo Welt#\\

Die Ausgabe von '\verb#ls#' ist nicht mehr in ``datei1'' enthalten, denn die Datei wurde bei der zweiten Ausgabenumleitung (hinter '\verb#echo#') überschrieben. Mit dem Doppelpfeil können wir eine umgeleitete Ausgabe an die Datei anhängen:\\
\verb#ls > datei1#\\
\verb#echo Hallo Welt >> datei1#\\
\verb#cat datei1#\\
$\Rightarrow$\\
... (Verzeichnisauflistung)\\
\verb#Hallo Welt#\\

\subsubsection{Ausgabeumleitung an Programme}
Sehen wir uns zunächst zwei weitere Unix-Befehle an, mit denen diese Art der Umleitung sinnvoll ist:
\begin{itemize}
  \item \textbf{wc} - ``word count'' (``Wörterzahl'') gibt die Anzahl von Zeilen, Wörtern und Zeichen in einer angegebenen Datei aus
  \item \textbf{tr} - ``translate'' (übersetze) ersetzt Zeichen in einem Datenstrom durch andere.
\end{itemize}

Das Kommando '\verb#wc#' kann auf Dateien angesetzt werden, um darin enthaltene Zeilen, Wörter und Zeichen zu zählen:\\
\verb#echo Hallo Welt > datei1#\\
\verb#echo Was geht ab? >> datei1#\\
\verb#wc datei1#\\
$\Rightarrow$\\
\verb# 2  5 24 datei1#\\

Die Datei hat demnach 2 Zeilen, 5 Wörter und insgesamt 24 Zeichen. Was ist nun, wenn wir eine solche Statistik z.B. für die Ausgabe von '\verb#ls#' haben wollen? Das Programm '\verb#wc#' ist in der Lage, seinen Text nicht nur aus einer Datei, sondern auch aus einer Umleitung zu lesen:\\
\verb#ls |wc#\\
$\Rightarrow$\\
\verb#     72      89     992#\\

Die angezeigten Zahlenwerte hängen natürlich davon ab, welches Verzeichnis wir uns von '\verb#ls#' ausgeben lassen. In diesem Fall haben wir 72 Zeilen ('\verb#ls#' listet genau 1 Objekt pro Zeile), 89 Wörter (einige Dateinamen hier enthalten also offenbar Leerzeichen) und insgesamt 992 Zeichen. Gucken wir uns die Zeile nochmal genauer an:\\

\begin{tabular}{l|r|l}
\textbf{Programmname} & \textbf{Shellumleitung} & \textbf{Programmname}\\
\hline
\verb#ls# & \verb#|# & \verb#wc#\\
\end{tabular}\\

Wir haben also zwei Programme gleichzeitig ausgeführt und dabei die Programmausgabe des ersten Programms ('\verb#ls#') zur Eingabe des zweiten Programms ('\verb#wc#') gemacht.\\

Einige Programme sind sogar darauf ausgelegt, nur auf diese Weise zu arbeiten, und gar nicht mit Dateien umzugehen. ein solches Programm ist '\verb#tr#':\\
\verb#echo Der Esel lauert im Teich. |tr s g#\\
$\Rightarrow$\\
\verb#Der Egel lauert im Teich.#\\

Das Programm '\verb#tr#' hat aus unserem Esel einen Egel gemacht. Betrachten wir kurz den Informationsfluss, der dabei Stattgefunden hat. Jedes Programm hat beim Start mindestens 3 Kanäle zum Austausch von Informationen:
\begin{itemize}
  \item \textbf{stdin} ``Standard Input'' ist der Kanal, auf dem Ein Programm Informationen liest.
  \item \textbf{stdout} ``Standard Output'' ist der Kanal, auf dem Ein Programm Informationen ausgibt.
  \item \textbf{stderr} ``Standard Error'' ist der Kanal, auf dem Ein Programm Fehlerausgaben schreibt.
\end{itemize}

Normalerweise ist 'stdin' eine Eingabe, die von der Tastatur gelesen wird, während 'stdout' und 'stderr' auf dem Terminal angezeigt werden. Die Shell ist in der Lage, diese Kanäle ``umzubiegen''. Betrachten wir den Befehl von eben noch einmal genau:\\

\begin{small}

\begin{tabular}{l|l|r|r|r|r|r|r}
\textbf{stdin von echo} &\textbf{Programm} &\textbf{Param1} &\textbf{Param2} &\textbf{Param3} &\textbf{Param4} & \textbf{Param5} &\textbf{stdout von echo} \\
\hline
(nichts) & \verb#echo# & Der & Esel & lauert & im & Teich. & Der Esel lauert im Teich. \\
\end{tabular}\\

\begin{tabular}{r}
\textbf{Umleitung} \\
\hline
\verb#|# \\
\end{tabular}\\

\begin{tabular}{l|l|r|r|r}
\textbf{stdin von tr} &\textbf{Programm} &\textbf{Param1} &\textbf{Param2} &\textbf{stdout von tr}\\
\hline
Der Esel lauert im Teich. & \verb#tr# &  s & g & Der Egel lauert im Teich.\\
\end{tabular}

\end{small}

%Ein Programm kann von sich aus diese Kanäle nach dem Start schließen, oder weitere Kanäle öffnen. Wenn wir beispielsweise an '\verb#wc#' eine Datei übergeben.
\end{document}
