Die Shell ist die zentrale Schnittstelle zwischen dir und dem Linux-System. Sie nimmt Befehle entgegen, leitet sie an das Betriebssystem weiter und gibt dir die Ergebnisse zurück. Wer versteht, wie stdin, stdout und Pipes funktionieren, beherrscht den Kern der Kommandozeile.

Was ist eine Shell?

Die Shell ist ein Programm, das Textbefehle vom Benutzer entgegennimmt und an den Linux-Kernel weiterleitet. Sie interpretiert die Eingabe, sucht nach ausführbaren Programmen, startet sie mit den angegebenen Argumenten und zeigt das Ergebnis an.

Gleichzeitig ist die Shell eine vollwertige Programmierumgebung. Mit Skripten lassen sich wiederkehrende Aufgaben automatisieren — von der Datensicherung bis zur Systemüberwachung. Ein Shell-Skript ist im Grunde eine Textdatei mit mehreren Befehlen, die die Shell Schritt für Schritt ausführt.

Die bekannteste Shell unter Linux ist die Bash (Bourne Again Shell). Sie ist auf den meisten Distributionen vorinstalliert und der Standard für interaktive Sessions sowie für Skripte. Wer sich mit Bash auskennt, kann auf praktisch jedem Linux- oder macOS-System arbeiten.

Weitere verbreitete Shells im Überblick:

ShellBeschreibungBesonderheitEinsatzgebiet
BashBourne Again ShellKompatibel mit sh, umfangreichste VerbreitungStandard auf Debian, Ubuntu, Fedora, macOS
ZshZ ShellErweiterte Autovervollständigung, globbing, ThemesPower-User, macOS-Standard seit Catalina
FishFriendly Interactive ShellSyntax-Highlighting, Vorschläge out of the boxEinsteiger, interaktive Sessions
DashDebian Almquist ShellMinimal, schnell, POSIX-konformAls /bin/sh verlinkt, für Skripte
KshKorn ShellKommerzieller Hintergrund, erweiterte FeaturesLegacy-Systeme, AIX, HP-UX

Welche Shell gerade aktiv ist, zeigt der Befehl:

Bash Aktive Shell anzeigen
echo $SHELL

Die aktive Shell für die laufende Session zeigt echo $0. Eine permanente Umstellung auf Zsh oder Fish erfolgt über chsh (change shell) und erfordert in der Regel einen erneuten Login.

Shell vs. Terminal

Die beiden Begriffe werden oft verwechselt, beschreiben aber völlig unterschiedliche Schichten:

Terminal (genauer: Terminal-Emulator) ist die grafische Anwendung, die du öffnest. Es verwaltet Fenster, Schriftarten, Farben und Tastatureingaben. Bekannte Beispiele: GNOME Terminal, Konsole (KDE), Alacritty, Windows Terminal, iTerm2 (macOS).

Shell ist das Programm, das innerhalb des Terminals läuft. Sie verarbeitet die eingegebenen Befehle, expandiert Variablen und Wildcards, sucht Programme im PATH und startet Prozesse. Die Shell ist es, die echo, ls oder grep ausführt.

Das bedeutet: Du kannst im selben Terminal die Shell wechseln, indem du zsh oder fish eingibst. Das Terminal-Fenster bleibt gleich, die Befehlsverarbeitung ändert sich. Umgekehrt kannst du das Terminal schließen, während die Shell in einer virtuellen Konsole (z. B. tty3) weiterläuft.

Wann brauche ich die Shell?

Die grafische Oberfläche reicht für viele Alltagsaufgaben aus. Sobald es aber um Wiederholbarkeit, Präzision oder Fernzugriff geht, wird die Shell unverzichtbar.

Server-Administration Headless-Server — also Rechner ohne Monitor, Tastatur und grafische Oberfläche — werden ausschließlich über die Shell verwaltet. Selbst auf Desktops ist die Shell der schnellste Weg, um Systemdienste zu steuern, Netzwerke zu konfigurieren oder Dateirechte zu ändern.

Automatisierung Sich wiederholende Aufgaben wie Datensicherungen, Log-Rotation oder die Bereitstellung von Anwendungen lassen sich als Shell-Skript speichern. Per Cron oder systemd-Timer werden sie zeitgesteuert ausgeführt — ohne menschliches Zutun.

Fehlersuche Log-Dateien durchsuchen, laufende Prozesse analysieren, Netzwerkverbindungen testen, Speicherverbrauch prüfen: All das geht in der Shell oft schneller und präziser als mit grafischen Werkzeugen. Pipes erlauben es, mehrere Werkzeuge zu einer Analyse-Pipeline zu verbinden.

Entwicklung Versionskontrolle mit Git, Build-Prozesse, Container-Steuerung mit Docker, Paketmanager wie npm oder pip — die meisten Entwicklungswerkzeuge werden primär auf der Kommandozeile bedient. Die IDE ruft im Hintergrund oft nichts anderes als Shell-Befehle auf.

Die drei Standardkanäle

Jedes Linux-Programm arbeitet mit drei Standardkanälen: stdin, stdout und stderr. Das Verständnis dieser Kanäle ist essenziell, um Befehle zu kombinieren, Ausgaben zu steuern und Fehler zu isolieren.

Standard-Eingabe (stdin)

stdin (Dateideskriptor 0) ist der Kanal, über den ein Programm Eingaben erhält. Standardmäßig ist er mit der Tastatur verbunden.

Bash Interaktive Eingabe
cat

Nach dem Start wartet cat auf Tastatureingaben und gibt jede Zeile direkt wieder aus. Das Programm endet, wenn du Strg + D drückst (EOF, End Of File). Das ist das Standard-Signal, das stdin schließt.

Bash Eingabe in Variable
read name

read liest eine Zeile von stdin und speichert sie in der Variablen name. Den Inhalt gibst du später mit echo aus:

Bash Variable ausgeben
echo "$name"
Output
eingegebener-wert

Die Eingabe lässt sich auch aus einer Datei umleiten:

Bash Eingabe aus Datei umleiten
cat < datei.txt

Hier wird der Inhalt von datei.txt über stdin an cat übergeben — das Programm merkt keinen Unterschied zur Tastatureingabe.

Standard-Ausgabe (stdout)

stdout (Dateideskriptor 1) ist der Kanal für reguläre Ausgaben. Standardmäßig erscheint die Ausgabe im Terminal.

Bash Ausgabe auf stdout
echo "Willkommen in der Shell!"

Mit dem Operator > leitest du stdout in eine Datei um. Der Operator überschreibt bestehende Inhalte:

Bash Ausgabe in Datei umleiten
echo "Hello, World!" > output.txt

Mit >> hängst du die Ausgabe an eine bestehende Datei an, anstatt sie zu überschreiben. Das ist das Standardmuster für Log-Dateien.

Standard-Fehlerausgabe (stderr)

stderr (Dateideskriptor 2) ist der Kanal für Fehlermeldungen. Er ist standardmäßig ebenfalls mit dem Terminal verbunden, lässt sich aber separat umleiten — ein entscheidender Vorteil gegenüber Systemen, die Ausgabe und Fehler nicht trennen.

Bash Fehlerausgabe in Datei
ls /nonexistent_directory 2> error.log

Hier landet die Fehlermeldung in error.log, während normale Ausgaben weiterhin im Terminal erscheinen. Ein häufiges Muster in Skripten ist die gleichzeitige Umleitung beider Kanäle in separate Dateien:

Bash stdout und stderr trennen
mein-skript.sh > ausgabe.log 2> fehler.log

Wenn du alle Ausgaben — egal ob normal oder Fehler — in dieselbe Datei schreiben willst, verwendest du &>:

Bash Alles in eine Datei
mein-skript.sh &> kombiniert.log

Pipes: Befehle verbinden

Eine Pipe (|) leitet die stdout eines Befehls direkt als stdin an den nächsten Befehl weiter. Das ist eines der mächtigsten Konzepte der Unix-Philosophie: kleine, spezialisierte Programme, die sich zu komplexen Workflows kombinieren lassen.

Bash Einfache Pipe
ls -la | grep "\.txt$"

Dieser Befehl listet alle Dateien auf und filtert nur die Zeilen, die auf .txt enden. grep liest dabei nicht aus einer Datei, sondern direkt aus der Ausgabe von ls.

Pipes lassen sich beliebig verketten:

Bash Verkettete Pipes
cat log.txt | grep "ERROR" | sort | uniq -c

Die Kette arbeitet Schritt für Schritt:

  1. cat log.txt — gibt den Inhalt der Log-Datei auf stdout aus
  2. grep "ERROR" — filtert Zeilen mit dem Wort “ERROR” und gibt sie weiter
  3. sort — sortiert die Zeilen alphabetisch
  4. uniq -c — zählt, wie oft jede eindeutige Zeile vorkommt

Ein weiteres nützliches Muster ist die Kombination von stderr-Umleitung und Pipe:

Bash stderr umleiten, dann pipen
find /etc -name "*.conf" 2>/dev/null | wc -l

Hier werden Berechtigungsfehler (stderr) nach /dev/null verworfen, während die gefundenen Dateien (stdout) gezählt werden. Das Muster 2>/dev/null ist Standard, wenn Fehlermeldungen die Ausgabe nicht verschmutzen sollen.

Grundlegende Befehle

Diese Befehle sind in jeder Shell verfügbar und bilden das Rückgrat der täglichen Arbeit. Die meisten gehören zu den GNU Coreutils und verhalten sich auf allen Linux-Distributionen identisch.

BefehlZweckWichtige Optionen
pwdAktuelles Verzeichnis anzeigen
lsDateien und Verzeichnisse auflisten-l (lang), -a (alle inkl. versteckte), -h (menschenlesbare Größen)
cdVerzeichnis wechselncd - (zurück zum vorherigen), cd ~ (zum Home-Verzeichnis)
touchLeere Datei erstellen oder Zeitstempel aktualisieren
mkdirVerzeichnis erstellen-p (Elternverzeichnisse mit anlegen)
rmDateien oder Verzeichnisse löschen-r (rekursiv), -f (ohne Rückfrage — mit extremster Vorsicht verwenden)
cpDateien oder Verzeichnisse kopieren-r (rekursiv), -i (vor Überschreiben fragen)
mvDateien verschieben oder umbenennen-i (vor Überschreiben fragen)
catDateiinhalte ausgeben-n (Zeilennummern), Verketten mehrerer Dateien
lessSeitenweise anzeigen mit Scrollen/suchbegriff (suchen), q (beenden)
headErste Zeilen anzeigen-n 20 (20 Zeilen statt 10)
tailLetzte Zeilen anzeigen-f (live verfolgen, z. B. für Log-Dateien)
grepNach Mustern suchen-i (ignoriere Groß-/Kleinschreibung), -r (rekursiv), -n (Zeilennummern)

Diese Befehle arbeiten alle mit stdin, stdout und stderr. Das bedeutet, du kannst sie mit Pipes kombinieren, Ausgaben in Dateien umleiten und sie in Skripten verwenden — unabhängig davon, welche Shell du nutzt.

Häufige Stolperfallen

Leerzeichen in Dateinamen ohne Anführungszeichen

Die Shell trennt Argumente an Leerzeichen. Der Befehl cp meine datei.txt ziel/ kopiert deshalb zwei Dateien — meine und datei.txt — nach ziel/, anstatt die Datei meine datei.txt zu kopieren. Korrekt ist die Umschließung mit doppelten Anführungszeichen: cp "meine datei.txt" ziel/. Das gilt für alle Befehle, die Dateipfade als Argumente erwarten. Auch Variablen, die Pfade enthalten, sollten in Anführungszeichen stehen: cp "$quelle" "$ziel".

`rm` löscht sofort und unwiderruflich

Anders als grafische Dateimanager hat rm keinen Papierkorb. rm wichtig.txt entfernt die Datei permanent, ohne Rückfrage. Für Verzeichnisse ist rm -rf /pfad besonders gefährlich — es löscht rekursiv und ohne Nachfrage. Best Practice: Vor dem Löschen wichtiger Dateien erst ein ls mit dem gleichen Muster ausführen, um zu prüfen, was betroffen wäre. Auf manchen Systemen ist rm als Alias auf rm -i konfiguriert, das fragt vor dem Löschen nach — verlassen sollte man sich darauf aber nicht.

`>` überschreibt Dateien stillschweigend

Der Umleitungsoperator > überschreibt bestehende Dateien, ohne zu warnen. echo "test" > wichtig.txt zerstört den vorherigen Inhalt von wichtig.txt. In der Bash kannst du mit set -o noclobber das versehentliche Überschreiben verhindern — dann verweigert die Shell die Umleitung mit cannot overwrite existing file. Um dennoch zu überschreiben, verwendest du dann >|. Für das Anhängen an bestehende Dateien ist >> die sichere Alternative, da sie nie etwas löscht.

Pipes verbergen Exit-Codes des ersten Befehls

In einer Pipe wie cmd1 | cmd2 siehst du nur den Exit-Code von cmd2. Wenn cmd1 fehlschlägt, aber cmd2 erfolgreich ist, wirkt der gesamte Befehl erfolgreich. Das ist in Skripten kritisch, weil if oder && dann falsche Annahmen treffen. Abhilfe schafft set -o pipefail in der Bash: Damit liefert die Pipe den Exit-Code des zuerst fehlgeschlagenen Befehls zurück. Das gehört in jedes ernsthafte Shell-Skript.

Shell-Variablen sind nicht automatisch Umgebungsvariablen

Die Zuweisung name=wert erzeugt nur eine Shell-Variable, die für das laufende Terminal sichtbar ist. Unterprozesse — also Programme, die du aus der Shell startest — sehen sie nicht. Erst export name=wert macht die Variable zu einer Umgebungsvariablen, die an Kind-Prozesse vererbt wird. Das ist der Grund, warum PATH in der Regel mit export gesetzt wird: Sonst würden Programme, die du startest, die Pfade nicht finden. Den Unterschied prüfst du mit env (zeigt nur Umgebungsvariablen) vs. set (zeigt alle Shell-Variablen).

`cat` für einzelne Dateien ist oft überflüssig

cat datei.txt | grep suchbegriff ist ein sogenannter Useless Use of Cat (UUOC). grep kann Dateien direkt lesen: grep suchbegriff datei.txt ist effizienter und übersichtlicher. Pipes sind mächtig, aber jede unnötige Pipe erzeugt einen zusätzlichen Prozess und verschleiert die Datenherkunft. Ausnahme: Wenn die vorherige Stufe der Pipe kein Datei-Argument akzeptiert, ist cat manchmal unvermeidlich.

Weiterführende Ressourcen

Externe Quellen

/ Weiter

Zurück zu Grundlagen

Zur Übersicht