Einleitung
Willkommen zur macOS Terminal Referenz
Das Terminal ist weit mehr als ein schwarzes Fenster mit grünem Text – es ist das mächtigste Werkzeug auf deinem Mac. Während die grafische Oberfläche ihre Berechtigung hat, ermöglicht das Terminal eine Kontrolle und Effizienz, die mit Mausklicks unerreichbar bleibt.
Warum das Terminal beherrschen?
Das macOS-Terminal bzw. die Shell (standardmäßig zsh seit macOS Catalina) ist die direkte und mächtigste Schnittstelle zum Betriebssystem. Es ermöglicht:
- Geschwindigkeit: Navigation mit der Tastatur – keine Mausklicks, keine Verzögerungen
- Automatisierung: Komplexe Aufgaben mit einem einzigen Befehl wiederholen
- Kontrolle: Zugriff auf (versteckte) Systemeinstellungen und Systemdateien
- Entwicklung: Konfiguration von Entwicklungsumgebungen, Verwaltung von Git-Repositories, Deployment von Code
- Fehleranalyse: Durchsuchen von Logs, Analysieren von Prozesse, Verstehen von Systeminformationen
- Server-Verwaltung: Effiziente Verwaltung von Cloud-Systemen und Remote-Servern
note
Mit dem Terminal hat man die volle Kontrolle über das System. Es ist kein Relikt aus vergangenen Zeiten, sondern das präziseste und schnellste Werkzeug des Betriebssystems.
Inhalte
Diese Referenz ist in vier Teile gegliedert:
Teil I: Grundlagen
Essentiellen Befehle, Verständnis für das Dateisystem, Konfiguration der Shell, eine Basis für effizientes Arbeiten im Terminal legen
Teil II: Fortgeschrittene Themen
Von Shell-Scripting über tmux bis zu ZLE-Widgets – hier wird tiefer eingetaucht und erklärt, wie du das Terminal zum persönlichen Produktivitäts-Multiplikator wird.
Teil III: Cheat Sheets
Schnellreferenzen für häufig verwendete Tools und Programmiersprachen – immer griffbereit.
Teil IV: Terminals, Shells und Erweiterungen
Moderne Terminal-Emulatoren, Shell-Erweiterungen und die neuesten CLI-Tools, welche die Arbeit noch angenehmer machen.
Wie diese Referenz genutzt werden kann
Diese Referenz ist als Nachschlagewerk konzipiert. Man muss sie nicht von vorne bis hinten durcharbeiten:
- Als Anfänger: Start mit Teil I und sequentielles Durcharbeiten der Grundlagen
- Als Fortgeschrittener: Direkt zu den Themen, die einen interessieren
- Im Alltag: Nutzung der Suchfunktion und Cheat Sheets als schnelle Referenz
Jedes Kapitel enthält praktische Beispiele, die man direkt in deinem Terminal ausprobieren kann.
Terminal und Dateisystem
1 Was ist das Terminal
Das Terminal ist ein Programm, dass eine Shell, d. h. einen Kommandozeileninterpreter, ausführt. macOS nutzt standardmäßig zsh (Z Shell). Es wird im folgenden davon ausgegangen, dass zsh verwendet wird.
Welche Shell genutzt wird, kann man dem folgenden Befehl geprüft werden:
echo $SHELL
2 Wichtige Konzepte/Begriffe
| Begriff | Bedeutung |
|---|---|
| Shell | Programm, das Befehle interpretiert (zsh, bash, fish etc.) |
| Prompt | Die Eingabeaufforderung, z. B. username@Mac ~ % |
| Pfad (Path) | Gibt an, wo im Dateisystem man sich befindest |
| Home-Verzeichnis | Pfad des persönlichen Bereichs: ~ oder /Users/<username> |
| Root | Das oberste Verzeichnis des Systems: / |
| Umgebungsvariablen | Werte, die Systemverhalten beeinflussen, z. B. PATH, HOME |
3 Dateisystem von macOS
3.1 Aktuelles Dateisystem: APFS (Apple File System)
Seit macOS 10.13 (High Sierra, 2017) ist APFS das Standard-Dateisystem für SSDs; seit macOS 10.15 (Catalina, 2019) auch für alle Laufwerke.
Merkmale:
-
Copy-on-Write (CoW): Änderungen an Dateien oder Metadaten erzeugen neue Kopien, was das System sicherer macht.
(Änderungen werden nicht direkt auf bestehende Daten geschrieben werden. Stattdessen legt das System beim Ändern von Dateien oder Metadaten eine neue Kopie der betroffenen Blöcke an und verweist erst danach auf sie. Dadurch bleiben alte Datenversionen solange erhalten, bis der Schreibvorgang erfolgreich abgeschlossen ist. Das schützt vor Datenverlust bei Stromausfall oder Absturz. Außerdem ermöglicht CoW Systemfunktionen wie Snapshots, bei denen ganze Dateisystemzustände nahezu ohne Speicheraufwand gespeichert werden.)
-
Snapshots: Das System kann zu bestimmten Zeitpunkten eingefroren werden (z. B. vor Systemupdates). Dadurch kann bei Problemen auf einen alten Zustand zurückgewechselt werden. Time Machine nutzt diese Funktion.
-
Space Sharing: Mehrere Volumes (z. B. “Macintosh HD” und “Macintosh HD – Data”) teilen sich denselben physischen Speicherplatz. Das spart Platz, da ungenutzter Speicher flexibel zwischen Volumes verteilt wird.
-
Verschlüsselung: Native Unterstützung für FileVault 2 und einzelne verschlüsselte Volumes. (FileVault 2 verschlüsselt das gesamte Systemvolume, schützt Daten bei Diebstahl und sorgt dafür, dass nur berechtigte Benutzer darauf zugreifen können.)
-
Case Sensitivity: Standardmäßig nicht case-sensitive (d. h.
Datei.txt = datei.txt), kann aber beim Formatieren geändert werden.
3.2 Wichtige Volumes und Partitionen
Seit macOS Catalina ist das System in mehrere logische Volumes aufgeteilt:
-
Macintosh HD: Systemvolume (read-only, geschützt durch SIP) (Das Systemvolume enthält das schreibgeschützte Betriebssystem inklusive aller Kernkomponenten, Frameworks und Standardprogramme.)
-
Macintosh HD – Data: Benutzer- und Programmdaten (beschreibbar) persönliche Dateien, Dokumente, Einstellungen und installierte Programme, z. B. in
/Users/<username>oder/Applications. -
Preboot, Recovery, VM: Hilfsvolumes für Boot, Wiederherstellung und Swap Preboot hilft beim Starten des Systems, Recovery ermöglicht Wiederherstellung und VM speichert Swap- bzw. Auslagerungsdateien temporär.
Mit dem Befehl diskutil wird die komplette Volume-Struktur angezeigt.
3.3 Systemschutz und Berechtigungen
macOS schützt kritische Systembereiche durch verschiedene Mechanismen, damit Systemdateien nicht versehentlich verändert werden können.
-
SIP (System Integrity Protection): Schützt Systemverzeichnisse und Kernel-Extensions. Nur im Recovery-Modus deaktivierbar.
-
Sandboxing: Viele Apps laufen in isolierten Containern, sodass sie nur auf erlaubte Dateien zugreifen können. Dies begrenzt Schäden durch fehlerhafte oder schadhafte Programme.
-
ACLs & POSIX Permissions: macOS verwendet klassische Unix-Rechte (
rwx, siehe ../SUMMARY) und erweiterte Access Control Lists (siehe ../SUMMARY). → Anzeigen mitls -le.
3.4 Mountpoints und Pfade
- Alle Volumes werden unter
/Volumes/eingehängt. - Netzlaufwerke oder externe Festplatten erscheinen dort automatisch.
- Systempfade wie
/System,/Libraryoder/usrsind meist Symlinks auf interne Strukturen des schreibgeschützten Systemvolumes.
4 Ordnerstruktur und wichtige Verzeichnisse
macOS basiert auf UNIX (BSD), daher folgt es grob der klassischen Unix-Hierarchie – erweitert um Apple-spezifische Pfade.
4.1 Systemebene (Root /)
| Ordner | Beschreibung |
|---|---|
/System | Enthält das Betriebssystem selbst (Frameworks, Libraries, Kernel-Komponenten). Schreibgeschützt |
/bin | Enthält grundlegende Benutzerbefehle, die auch im Einzelbenutzermodus verfügbar sein müssen, wie beispielweise ls, cp, mv, rm, bash oder zsh. Diese Tools sind für den täglichen Gebrauch und die Systemreparatur unverzichtbar. |
/sbin | Beinhaltet System- und Verwaltungsbefehle, die normalerweise Administratorrechte erfordern, z. B. ifconfig, mount, fsck oder reboot. Diese Tools dienen zur Systemwartung und -konfiguration. |
/usr/bin | Hier liegen zusätzliche Benutzerprogramme und Utilities, die nicht unbedingt zum Start des Systems benötigt werden, z. B. grep, awk, vim, curl, python, git usw. |
/usr/sbin | Ergänzt /usr/bin um administrative Befehle wie apachectl, postfix, cron oder syslogd. Sie werden meistens von Diensten oder Admins verwendet, nicht von normalen Nutzern. |
/usr/local | Für manuell installierte Tools und Homebrew |
/Library | Systemweite Ressourcen: LaunchAgents, Fonts, Extensions, Preferences |
/Applications | Systemweite Programme (z. B. Safari, Mail) |
/Volumes | Mountpoint für externe Laufwerke, Netzfreigaben, Disk-Images |
/private | Enthält temporäre Daten (/private/tmp, /private/var) und Logdateien. Viele klassische UNIX-Verzeichnisse (/etc, /tmp, /var) sind Symlinks hierhin |
note
Viele dieser Pfade sind symbolisch mit /System/Volumes/Data/usr/... verknüpft, da das eigentliche Systemvolume seit macOS Catalina schreibgeschützt ist.
4.2 Benutzerverzeichnisse (/Users)
Jeder Benutzer hat ein eigenes Homeverzeichnis, z. B. /Users/john.
Wichtige Unterordner:
| Ordner | Beschreibung |
|---|---|
Desktop | Dateien auf dem Schreibtisch. |
Documents | Eigene Dokumente. |
Downloads | Standard-Download-Ordner. |
Library | Benutzerbezogene Einstellungen, Caches, LaunchAgents, App-Daten. |
Pictures, Music, Movies | Medienordner (z. B. für Fotos oder iTunes). |
note
Der Ordner ~/Library ist standardmäßig versteckt. Anzeigen mit:
chflags nohidden ~/Library
important
Tilde (~)
Das Zeichen ~ steht im Terminal als Abkürzung für das aktuelle Benutzerverzeichnis, z. B. /Users/john. Es wird getippt mit ⌥ N.
Mit cd ~ kann man in das Homeverzeichnis zu wechseln oder mit cd ~/Documents, direkt in den Dokumente-Ordner.
4.3 Weitere wichtige Orte
| Pfad | Zweck |
|---|---|
/etc/hosts | Lokale Hostname-Zuordnungen. |
/var/log/ | System- und Anwendungs-Logs. |
/private/tmp | Temporäre Dateien (automatisch geleert). |
/Library/LaunchAgents und /Library/LaunchDaemons | Automatische Dienste und Hintergrundprozesse. |
/usr/share/ | Gemeinsame Systemdateien (z. B. Manpages). |
5 macOS unter der Haube
macOS basiert auf UNIX/BSD und Darwin. Unter der Haube steuern Launchd, Logging und Sicherheitsmechanismen, wie Gatekeeper oder TCC, den Systembetrieb.
5.1 Launchd und Dienste
launchd ist das zentrale Init-System von macOS und ersetzt klassische Systeme wie systemd oder init. Es startet Prozesse beim Booten, nach Bedarf oder im Benutzerkontext. Dienste werden über Property-List-Dateien (.plist) definiert.
Speicherort der .plist-Dateien:
/System/Library/LaunchDaemons,/Library/LaunchAgentsoder~/Library/LaunchAgents
Aktive Dienste anzeigen:
launchctl list
Manuelle Steuerung von Diensten:
launchctl load/unload
Damit verwaltet macOS sowohl System- als auch Benutzerprozesse konsistent.
5.2 Systemprotokolle und Logging
macOS verwendet seit Sierra ein Unified Logging System, das alle Logmeldungen zentral verfügbar macht.
Vergangene Ereignisse anzeigen:
log show
Live Ansicht von Ereignissen:
log stream
Diese Logs sind strukturiert und nach Subsystemen gegliedert, z. B. “network”, “kernel” oder “security”.
Ältere Textlogs existieren weiterhin unter /var/log/, z. B. system.log. Entwickler oder Administratoren können mit Filtern wie
log show --predicate 'eventMessage contains "error"'
gezielt Fehlermeldungen finden.
5.3 Netzwerk & Namensauflösung
macOS bietet zahlreiche Kommandozeilenwerkzeuge zur Verwaltung und Diagnose von Netzwerken. Neben klassischen UNIX-Befehlen wie ping und traceroute sind vor allem networksetup und scutil für Systemkonfigurationen relevant.
Über den Dienst mDNSResponder (Bonjour) werden Geräte im lokalen Netz automatisch erkannt. Die Datei /etc/hosts erlaubt lokale DNS-Zuordnungen.
| Befehl | Beschreibung | Beispiel |
|---|---|---|
networksetup | Zeigt oder ändert Netzwerk-Interfaces, Dienste und DNS-Einstellungen | networksetup -listallhardwareports |
ifconfig | Zeigt IP-Konfigurationen und Netzwerkinterfaces an oder konfiguriert sie manuell | ifconfig en0 |
ping | Prüft, ob ein Host erreichbar ist | ping google.com |
traceroute | Zeigt die Route von Paketen zum Zielhost an | traceroute apple.com |
scutil --dns | Listet DNS-Server, Suchdomänen und aktuelle Resolver-Einstellungen auf | scutil --dns |
cat /etc/hosts | Zeigt lokale Hostnamen-Zuordnungen an oder ermöglicht deren Bearbeitung | sudo nano /etc/hosts |
5.4 Sicherheitsmechanismen
Die folgenden Mechanismen/Schutzebenen wirken zusammen, um das System vor Malware und unautorisierten Änderungen zu schützen:
- Gatekeeper blockiert unsignierte oder nicht-notarisierte Apps.
- SIP (System Integrity Protection) schützt Systemverzeichnisse und Kernel-Komponenten selbst vor Root-Änderungen.
- Notarization stellt sicher, dass Apps von Apple geprüft wurden.
- Sandboxing und TCC (Transparency, Consent & Control) begrenzen App-Zugriffe auf Dateien, Kamera, Mikrofon usw.
5.5 Prozess- & Systemüberwachung
Es gibt mehrere Tools, um Prozesse, Ressourcen und Systemzustände zu überwachen. Während ps und top Standardbefehle aus der UNIX-Welt sind, liefert htop eine moderne, farbige Ansicht. Befehle wie lsof, vm_stat und powermetrics helfen bei tiefergehender Analyse von Performance, Speicher oder Energieverbrauch.
| Befehl | Beschreibung | Beispiel |
|---|---|---|
ps aux | Listet alle laufenden Prozesse mit Benutzer, PID, CPU- und Speicherverbrauch | ps aux |
top | Zeigt Systemauslastung in Echtzeit an (ähnlich Task-Manager) | top |
htop | Erweiterte, interaktive Prozessansicht mit Sortierung, Suche und Farben | htop |
lsof | Listet offene Dateien, Ports und Sockets | sudo lsof -i :80 |
vm_stat | Zeigt Statistik zur Speichernutzung und Paging-Aktivität | vm_stat |
powermetrics | Misst Energieverbrauch, CPU-Last, GPU-Aktivität und Temperatur | sudo powermetrics --samplers cpu_power |
Die wichtigsten Befehle
1 Navigation
| Befehl | Beschreibung |
|---|---|
pwd | Zeigt aktuelles Verzeichnis |
ls | Listet Dateien/Ordner |
cd | Wechselt Verzeichnis |
history | Zeigt den Befehlsverlauf an |
1.1 ls-Befehl
ls -l # Detaillierte Liste mit Berechtigungen, Datum, Größe, ...
ls -a # Zeigt auch versteckte Dateien und Ordner an
ls -la # Kombination: Detaillierte Liste inkl. versteckter Elemente
ls -lh # Liste mit Größenangaben in passender Einheit (KB, MB, GB)
ls -lah # Kombination
ls -lt # Sortierung nach Änderungsdatum
ls -lS # Sortierung nach Dateigröße
ls -l <pfad> # Anzeigen von Dateien/Ordner des gegebenen Pfads
1.2 cd-Befehl
cd Documents # Wechselt in den Unterordner Documents
cd ~/Downloads # Wechselt in den Ordner Downloads im Homeverzeichnis
cd / # Wechselt in Hauptverzeichnis
cd ~ # Wechselt in das Homeverzeichnis
cd .. # Wechselt ins Eltern-Verzeichnis
cd ../.. # Geht zwei Ebenen nach oben
cd - # Springt zum letzten Verzeichnis zurück
note
Unterschied zwischen ~ und $HOME
Die Tilde (~) ist eine Shell-Abkürzung für das Home-Verzeichnis, während $HOME eine Umgebungsvariable ist, die von Programmen und Skripten verwendet wird. Beide zeigen auf das Home-Verzeichnis des aktuell angemeldeten Benutzers, sind jedoch unterschiedlich implementiert.
Siehe auch: ~ vs. $HOME
1.3 history-Befehl
history # Zeigt die letzten ausgeführten Befehle an
history | grep "cal" # Zeigt die letzten Befehle an, passen zum Suchbegriff
!123 # Führt Befehl 123 erneut aus
!! # Führt den letzten Befehl erneut aus
2 Dateien und Ordner
| Befehl | Beschreibung | Beispiel |
|---|---|---|
touch | Erstellt leere Datei(ein) | touch test1.txt test2.txt |
mkdir | Erstellt Verzeichnis(se) | mkdir Projekte Archiv |
cp | Kopiert Datei/Ordner | cp quelle.txt ziel.txt |
mv | Verschiebt oder benennt um | mv alt.txt neu.txt |
rm | Löscht Datei(en) und Ordner | rm test1.txt test2.txt |
rm -r | Löscht Verzeichnis rekursiv | rm -r Ordner |
achtung
Der Befehl rm löscht unwiderruflich – ohne Papierkorb!
Soll das Löschen bestätigt werden, muss der interaktive Modus verwendet werden:
>rm -i test.txt
>```
</div>
<div class="mdbook-callouts mdbook-callouts-tip">
<p class="mdbook-callouts-title">
<span class="mdbook-callouts-icon"></span>
tip
</p>
Bevor mehrere Dateien gelöscht werden, sollen die Auswirkungen des zugehörigen Befehls geprüft werden. Beispiel:
```zsh
ls *.py
rm *.py
2.1 mkdir-Befehl
mkdir NeuerOrdner # Erstellt einen Ordner
mkdir Ordner1 Ordner2 # Erstellt mehrere Ordner
mkdir -p Fotos/2025/10/29 # Erstellt Ordner + Unterordner
Brace Expansion für effiziente Stapelerstellung:
Geschweifte Klammern ermöglichen die schnelle Erstellung mehrerer ähnlicher Elemente:
mkdir Tag_{01..03} # Erstellt: Tag_01, Tag_02, Tag_03
mkdir {Januar,Februar,März} # Erstellt drei Monatsordner
touch datei_{a,b,c}.txt # Erstellt: datei_a.txt, datei_b.txt, datei_c.txt
echo {01..05} # Zeigt: 01 02 03 04 05
cp dokument.txt{,.backup} # Kopiert nach dokument.txt.backup
Kombinationen sind ebenfalls möglich:
mkdir -p Projekt/{src,tests,docs}/{python,rust}
# Erstellt: Projekt/src/python, Projekt/src/rust,
# Projekt/tests/python, Projekt/tests/rust,
# Projekt/docs/python, Projekt/docs/rust
2.2 cp- und mv-Befehl
cp quelle.txt ziel.txt # Kopiert eine Datei
cp -i quelle.txt ziel.txt # Fragt nach bevor überschrieben wird
cp -r Ordner1 Ordner2 # Kopiert einen kompletten Ordner (rekursiv)
cp *.txt Text # Kopiert alle Dateien mit der Endung .txt
Gleiche Syntax beim mv-Befehl.
3 Arbeiten mit Texten und Dateien
| Befehl | Funktion | Beispiel |
|---|---|---|
cat | Zeigt den Inhalt von Dateien (ohne Editor) | cat datei1.txt datei2.txt |
less | Scrollbare Ansicht | less datei.txt |
head / tail | Zeigt Anfang/Ende | head -n 20 datei.txt |
wc | Zählt Zeilen, Wörter, Zeichen | wc -l datei.txt |
diff | Vergleicht Dateien | diff a.txt b.txt |
find | Sucht Dateien | find . -name "*.txt" |
nano | Datei im Texteditor im Terminal öffnen | nano datei.txt |
grep | Sucht nach Textmustern in Dateien | grep "Fehler" log.txt |
open | Öffnet Datei/Ordner im Finder | open . |
open -a <App> | Öffnet Datei/Ordner in bestimmter App | open -a ForkLift . |
Alternative zu less datei.txt:
cat datei.txt | more
3.1 Navigation bei Anzeige über less-Befehl
- Leertaste: Nächste Seite
b: Vorherige Seite/: Vorwärts suchen?: Rückwärts suchenq: Beenden
3.2 head- und tail-Befehl
head datei.txt # Zeigt die ersten 20 Zeilen
head -n 20 datei.txt # Zeigt die ersten 20 Zeilen
tail datei.txt # Zeigt die letzten 10 Zeilen
tail -n 20 datei.txt # Zeigt die letzten 20 Zeilen
3.3 Dateiinhalt in Echtzeit anzeigen
Änderungen in Echtzeit können mit folgendem Befehl verfolgt werden:
tail -f info.log
Dies funktioniert jedoch nicht immer. Viele Editoren speichern Änderungen nicht direkt in der bestehenden Datei, sondern erstellen eine temporäre Datei, schreiben den neuen Inhalt hinein, löschen die alte Datei und benennen die neue Datei auf den alten Namen um. Dabei ändert sich die inode (Datei-Identität im Dateisystem). Abhilfe schafft -F (follow name). Es wird erkannt, wenn die Datei ersetzt wurde und folgt automatisch der neuen Datei.
tail -F info.log
Hierbei wird jedoch immer der neue Dateiinhalt unter den alten geschrieben. Dies wird schnell unübersichtlich. Eine bessere Lösung ist mit dem Befehl watch möglich. Diese muss ggf. noch installiert werden:
brew install watch
Anschließend kann der Dateiinhalt wie folgt überwacht werden:
watch -n 1 "clear && cat info.log"
-n 1: alle 1 Sekunden aktualisierenclear: Ausgabe löschencat test.txt: Dateiinhalt anzeigen
Nutzt man dies öfters, empfiehlt sich die Erstellung eines Alias:
alias watchfile='watch -n 1 "clear && cat $1"'
Verwendung mit:
watchfile info.log
3.4 find-Befehl
find . -name "*.txt" # Findet alle .txt-Dateien
find . -name "rechnung.pdf" # Findet die Datei rechnung.pdf
find . -type f -size +5M # Findet Dateien größer als 5 MB
find . -name "*.*" -mtime -7 # Dateien, die in den letzten 7 Tagen verändert wurden
find . -empty # Findet leere Dateien und Ordner
3.5 grep-Befehl
grep "Januar" notiz.txt # Sucht in einer Datei
grep -r "Januar" notiz.txt # Sucht rekursiv in einem Ordner
grep -n "Januar" notiz.txt # Zeigt alle Zeilen inkl. Nr. mit dem Suchwort
grep -c "Januar" notiz.txt # Zählt die Anzahl der Vorkommen des Suchworts
grep -i "Januar" notiz.txt # Berücksichtigt Groß- und Kleinschreibung
3.6 Prozesse, Systeme und Netzwerk
3.7 Prozesse
| Befehl | Beschreibung | Beispiel |
|---|---|---|
top | Live-Systemüberwachung | top |
htop | Live-Systemüberwachung (interaktiv, in Farbe) | htop |
ps | Zeigt aktive Prozesse | ps aux |
kill | Beendet Prozess | kill 1234 |
killall | Beendet alle Prozesse eines Namens | killall Safari |
3.8 top-Befehl
Kurzbefehle:
o: Nach anderer Spalte sortieren (odrücken und Spaltenname eingeben)q: Beenden
Alternative: htop
htop liefert eine interaktive Anzeige in Farbe.
Installation:
brew install htop
3.9 ps-Befehl
ps # Zeigt die eigenen Prozesse
ps aux # Zeigt alle Prozesse mit Details
ps aux | grep Safari # Zeigt bestimmte Prozesse
3.10 System und Hardware
| Befehl | Beschreibung |
|---|---|
df -h | Speicherplatz aller Laufwerke anzeigen |
du -sh * | Größe von Ordnern anzeigen |
uname | Anzeige von Systeminformationen |
uptime | Zeigt Laufzeit und Systemlast |
whoami | Aktueller Benutzer |
date | Aktuelles Datum/Zeit |
cal | Zeigt einen Kalender an |
say "Hallo" | macOS sagt Text laut (praktisch für Testzwecke) |
3.11 du-Befehl
du -sh * | sort -h # Größe von Ordnern und Dateien aufsteigend sortiert
du -sh * | sort -hr # Absteigend sortiert
du -sh * | sort -hr | head -5 # Beschränkung auf die 5 größten Elemente
3.12 uname-Befehl
uname # Zeigt den Kernelnamen an (i. d. R. "Darwin")
uname -a # Alle verfügbaren Systeminformationen
uname -s # Gleiche ausgabe wie bei uname
uname -r # Kernel-Version
uname -v # Kernel-Buildversion
uname -m # Machine hardware name
uname -n # Rechnername (Hostname)
uname -p # Prozessortyp (machmal leer)
uname -o # Betriebssystem
3.13 date-Befehl
date # Zeigt Datum+Zeit; z. B.: Thu Oct 30 21:53:42 CET 2025
date "+%Y-%m-%d" # Zeigt Datum, z. B.: 2025-10-30
date "+%H:%M:%S" # Zeigt Uhrzeit, z. B.: 21:53:42
3.14 cal-Befehl
cal # Aktueller Monat
cal 2026 # Bestimmtes Jahr
cal 01 2026 # Bestimmter Monat
Beispielausgabe:
January 2026
Su Mo Tu We Th Fr Sa
1 2 3
4 5 6 7 8 9 10
11 12 13 14 15 16 17
18 19 20 21 22 23 24
25 26 27 28 29 30 31
3.15 Netzwerk
| Befehl | Beschreibung | Beispiel |
|---|---|---|
ping | Testet Verbindung | ping google.com |
ifconfig | Zeigt Netzwerkschnittstellen | ifconfig |
curl | HTTP-Anfragen senden | curl https://example.com |
scp | Kopiert Dateien über SSH | scp file.txt user@host:/path |
ssh | Verbindung zu Server | ssh user@ip |
Lokale IP-Adresse(n) anzeigen:
ifconfig | grep "inet "
3.16 curl-Befehl
curl ist ein vielseitiges Tool zum Abrufen oder Senden von Daten über HTTP, HTTPS, FTP und viele andere Protokolle. Es eignet sich sowohl zum einfachen Testen von Webseiten als auch für API-Aufrufe.
Beispiele:
# Webseite abrufen und im Terminal anzeigen
curl https://example.com
# Datei herunterladen
curl -O https://example.com/datei.zip
# API-Aufruf mit Header
curl -H "Authorization: Bearer TOKEN" https://api.example.com/data
Häufig verwendete Optionen:
-I: nur Header anzeigen-L: Redirects folgen-d: POST-Daten senden
4 Job-Control (fg, bg, jobs, &)
Job-Control ermöglicht die Verwaltung von Prozessen, die im Hintergrund oder Vordergrund laufen. Dies ist besonders nützlich bei langläufigen Aufgaben oder wenn man mehrere Programme parallel ausführen möchte.
4.1 Grundlegende Konzepte
-
Vordergrundprozess (Foreground): Prozess, der gerade aktiv ist und das Terminal blockiert
-
Hintergrundprozess (Background): Prozess, der im Hintergrund läuft, während das Terminal weiter nutzbar bleibt
-
Job: Eine vom Terminal gestartete Aufgabe (kann mehrere Prozesse enthalten)
4.2 Befehle
| Befehl | Beschreibung |
|---|---|
jobs | Zeigt alle Jobs der aktuellen Shell |
fg | Holt einen Job in den Vordergrund |
bg | Setzt einen angehaltenen Job im Hintergrund fort |
& | Startet einen Befehl direkt im Hintergrund |
STRG + Z | Hält den aktuellen Vordergrundprozess an |
4.3 Beispiele
Prozess im Hintergrund starten:
python script.py &
Das & am Ende startet den Befehl sofort im Hintergrund. Das Terminal bleibt nutzbar.
Laufenden Prozess anhalten und in Hintergrund verschieben:
python script.py
# STRG + Z drücken (Prozess wird angehalten)
bg
Alle Jobs anzeigen:
jobs
Beispielausgabe:
[1] + running python script.py
[2] - suspended vim dokument.txt
Bestimmten Job in den Vordergrund holen:
fg %1 # Job 1 in den Vordergrund
fg %2 # Job 2 in den Vordergrund
fg # Letzten Job in den Vordergrund
Hintergrundprozess beenden:
kill %1 # Beendet Job 1
4.4 Praktische Anwendungsfälle
Mehrere Editoren gleichzeitig:
vim config.txt &
vim script.py &
jobs
Langläufige Aufgabe im Hintergrund:
find / -name "*.log" > logs.txt 2>&1 &
Zwischen mehreren Aufgaben wechseln:
python server.py
# STRG + Z
bg
vim main.py
# STRG + Z
jobs
fg %1 # Zurück zum Server
Arbeitsumgebung und Konfiguration
1 Der which-Befehl
Der Befehl which zeigt den vollständigen Pfad des Kommandos, das übergeben wird:
which <befehlsname>
Gibt man einen Befehl im Terminal ein, sucht die Shell in allen Verzeichnissen der PATH-Variable nach einer Datei mit diesem Namen. which tut dies ebenfalls. Jedoch wird der Befehl nicht ausgeführt sondern sein Speicherort ausgegeben.
Beispiel:
which brew
liefert:
/opt/homebrew/bin/brew
Wird nach einem Shell-Builtin (einem eingebauten Befehl, welcher kein separates Programm ist) wie beispielsweise cd oder echo gesucht, wird folgendes ausgegeben:
cd: shell built-in command
Vergleich mit ähnlichen Befehlen:
| Befehl | Zweck |
|---|---|
which <cmd> | Zeigt, wo auf dem Dateisystem ein ausführbares Programm gefunden wird. |
command -v <cmd> | Zeigt, wie die Shell den Befehl auflöst (auch für Builtins/Aliase). |
type <cmd> | Noch detailliertere Information über den Befehlstyp. |
2 Umgebungsvariablen
Anzeige einer Umgebungsvariable:
echo $PATH
Erweiterung von $PATH:
export PATH=$PATH:/usr/local/bin
2.1 Dauerhafte Speicherung
Nach einem Neustart sind zusätzlich hinzugefügte Pfade jedoch wieder weg. Sollen sie dauerhaft in der PATH-Variable bleiben, muss der export-Befehl in die .zshrc-Datei geschrieben werden (siehe auch Abschnitt “Die .zshrc-Datei”).
Wird die .zshrc-Datei jedoch mehr neugeladen (source ~/.zshrc), werden zusätzliche Pfade erneut hinzugefügt und kommt somit mehrfach vor. Die kann zu Problemen führen. Dieses Verhalten vermeidet man, indem vorher geprüft wird, ob der Pfad schon vorhanden ist:
# --- Custom PATH entries ------------------------------------------
# Define paths in array
CUSTOM_PATHS=(
"/Applications/Visual Studio Code.app/Contents/Resources/app/bin"
# "/add/additional/paths/here" (without comma; semicolon)
)
# Add all paths from CUSTOM_PATHS to PATH if it doesn't exist
for dir in "${CUSTOM_PATHS[@]}"; do
if [-d "$dir" && ":$PATH:" != *":$dir:"*](-d%20"$dir"%20&&%20":$PATH:"%20!=%20*":$dir:"*.md); then
export PATH="$PATH:$dir"
fi
done
# ------------------------------------------------------------------
2.2 ~ vs. $HOME
| Symbol | Bedeutung | Typ | Beispielwert |
|---|---|---|---|
~ | Kürzel für das Home-Verzeichnis des aktuellen Benutzers | Shell-Abkürzung (Shell Expansion) | /Users/max |
$HOME | Umgebungsvariable, die den Pfad zum Home-Verzeichnis enthält | Variable im Shell-Umfeld (Environment Variable) | /Users/max |
*~ (Tilde):
- Wird von der Shell (
zsh,bashetc.) automatisch expandiert. - Funktioniert nur an positionsabhängigen Stellen (z.B. nicht innerhalb von Anführungszeichen “ “).
- Wird häufig für Navigation verwendet:
cd ~
cd ~/Downloads
ls ~
Die Shell ersetzt ~ intern automatisch durch /Users/<username>.
Sonderformen:
~user # Home-Verzeichnis eines anderen Users (wenn zugreifbar)
~+ # aktuelles Verzeichnis
~- # vorheriges Verzeichnis
$HOME:
- Eine Umgebungsvariable, die den kompletten Pfad enthält.
- Wird von Programmen, Skripten und Konfigurationsdateien benötigt.
- Funktioniert auch innerhalb von Strings und Skripten:
echo $HOME
cd $HOME/Documents
export PATH="$PATH:$HOME/bin"
In vielen Programmen ist $HOME die bevorzugte Form, weil sie immer eindeutig ist, auch wenn die Shell keine Tilde-Ersetzung durchführt.
note
Zusammenfassung:
~= Komfortabler Shell-Shortcut für das persönliche Verzeichnis$HOME= Variable, die das Home-Verzeichnis systemweit speichert- Funktional oft identisch, technisch jedoch unterschiedlicher Mechanismus
3 Die .zshrc-Datei
Die Datei .zshrc ist die zentrale Konfigurationsdatei der Z-Shell (zsh). Sie wird bei jedem Start eines neuen interaktiven Terminalfensters automatisch geladen und ausgeführt. Darin lassen sich Befehle, Einstellungen, Umgebungsvariablen und Aliase dauerhaft speichern.
3.1 Speicherort
Die Datei liegt standardmäßig im Home-Verzeichnis des Benutzers:
~/.zshrc
Sollte sie nicht existieren, kann sie wie folgt erstellt werden:
touch ~/.zshrc
3.2 Zweck
In dieser Datei steht alles, was bei einem Terminalstart automatisch ausgeführt werden soll.
| Typ | Beispiel |
|---|---|
| Aliase | alias ll='ls -lah' |
| Umgebungsvariablen | export PATH="/opt/homebrew/bin:$PATH" |
| Eigene Funktionen | greet() { echo "Hallo $USER"; } |
| Prompt-Anpassungen | PROMPT='%n@%m %1~ %# ' |
| Themen / Plugins (oh-my-zsh) | source $ZSH/oh-my-zsh.sh |
| Autostart von Tools | eval "$(brew shellenv)" |
3.3 Änderungen übernehmen
Damit Änderungen wirksam werden, muss das Terminal neugestartet oder die Datei neugeladen werden.
Neuladen von ~/.zshrc:
source ~/.zshrc
Nützliches Aliase zum Bearbeiten und Neuladen von ~/.zshrc:
alias editrc="nano ~/.zshrc"
alias reloadrc="source ~/.zshrc"
3.4 Vergleich mit anderen Startdateien
| Datei | Ladezeitpunkt | Beschreibung |
|---|---|---|
~/.zshrc | bei jedem neuen interaktiven Shell-Start | Hauptdatei für zsh-Konfiguration |
~/.zprofile | nur Login-Shells | ähnlich wie .bash_profile, selten nötig |
~/.zlogin | am Ende einer Login-Shell | wird nach .zprofile geladen |
~/.zshenv | immer, auch bei nicht-interaktiven Shells | für globale Umgebungsvariablen |
~/.zlogout | beim Verlassen einer Login-Shell | Aufräumarbeiten (z. B. Logs, Cache) |
note
Die .zshrc ist das Herzstück der Shell-Konfiguration. Alles, was in jedem Terminal automatisch verfügbar sein soll – Aliase, PATH, Funktionen, Themes – gehört in diese Datei.
tip
Verschieben der .zshrc:
Die .zshrc kann wie folgt verschoben und durch einen Symlink ersetzt werden (z. B. wenn sie teil eines Repositories werden soll):
mv ~/.zshrc ~/dotfiles/zshrc
ln -s ~/dotfiles/zshrc ~/.zshrc
Skript einbinden
. ~/.config/zsh/aliases.zsh
Admin-Rechte (sudo)
Ist man als normaler Benutzer angemeldet kann ein Befehl mit Administrator-Rechten ausgeführt werden, indem sudo (superuser do) vorangestellt wird. Da macOS ein UNIX-basiertes System ist, sind viele Systembefehle nur mit Admin-Rechten ausführbar. Sie sind auch erforderlich für den Zugriff auf geschützte Systemdateien und -einstellungen.
1 Syntax
sudo <befehl> [optionen] [argumente]
Bei der ersten Ausführung von sudo wird nach dem Administratorpasswort gefragt.
2 Beispiele
Ordner /usr/local/test mit Administratorrechten erstellen:
sudo mkdir /usr/local/test
Systemverzeichnisse ändern:
sudo nano /etc/hosts
→ Bearbeitung der Host-Datei, um z. B. Webseiten umzuleiten.
Dienste starten/stoppen:
sudo launchctl load /Library/LaunchDaemons/meindienst.plist
Systemweite Berechtigungen ändern:
sudo chmod 755 /usr/local/bin/meinprogramm
Dateien löschen, die geschützt sind:
sudo rm -rf /Pfad/zur/Datei
caution
Den Befehl sudo sollte man nur verwenden, wenn man genau weiß, was man tut. Eine falsche Verwendung kann das System beschädigen!
3 Root-Shell und Shell mit Root-Rechten
sudo speichert die Authentifizierung kurzfristig (standardmäßig 5 Minuten = 300 Sekunden). Für häufige Admin-Aufgaben eignet sich eine Root-Shell (sudo -i) oder eine Shell mit Root-Rechten (sudo -s).
3.1 Root-Shell (sudo -i = login shell as root)
Es wird simuliert, dass man als Root-Benutzer eingeloggt ist, fast wie bei einem echten Root-Login.
Wichtige Eigenschaften:
- Es werden die Umgebungsvariablen des Root-Benutzers geladen (
PATH,HOME, usw.). - Man landet im Home-Verzeichnis des Root-Benutzers (
/var/root). - Es werden die Shell-Startdateien vom Root-Benutzer genutzt (
.profileund.bashrcbzw..zshrc)
sudo -i
- Prompt wechselt, z. B. von
cgroening@macbook ~ %zumacbook:~ root# echo $HOMEzeigt den Ordner/var/root
3.2 Shell mit Root-Rechten (sudo -s = run shell as root)
Man erhält eine Shell mit Root-Rechten.
Aber:
- Die eigenen Umgebungsvariablen bleiben aktiv.
- Man verbleibt im aktuellen Benutzerverzeichnis.
- Die Startdateien des Root-Benutzers werden nicht geladen.
sudo -s
- Prompt wechselt, z. B. von
cgroening@macbook ~ %zuroot@macbook ~ # echo $HOMEzeigt den Ordner/Users/cgroening
3.3 Zusammenfassung
| Option | Shelltyp | Verzeichnis | Umgebungs- variablen | Startdateien geladen? | Prompt |
|---|---|---|---|---|---|
- | Normale Shell | Benutzer-Home | cgroening@macbook ~ % | ||
sudo -i | Login-Shell | Root-Home | Root | Ja | macbook:~ root# |
sudo -s | Non-Login | Benutzer-Home | Eigene | Nein | root@macbook ~ # |
info
sudo -i vs sudo -s
- Will man komplett wie Root arbeiten, inklusive
PATH&HOME→sudo -i - Willst man nur temporär Root-Rechte, aber mit der eigenen Umgebung →
sudo -s
4 Übersicht
| Befehl | Funktion |
|---|---|
sudo <befehl> | Führt einen Befehl als Administrator aus |
sudo -i | Öffnet eine Root-Shell |
sudo -s | Öffnet Shell mit Root-Rechten |
sudo !! | Wiederholt letzten Befehl mit sudo |
sudo -v | Erneuert den sudo-Timer, ohne einen Befehl auszuführen |
sudo -k | Löscht sofort alle gespeicherten Authentifizierungen |
exit | Verlässt die Root-Shell bzw. Shell mit Root-Rechten |
Berechtigungen (chmod) und Besitz (chown)
1 chmod
1.1 Rechte und Benutzergruppen
chmod steht für change mode. Mit diesem Befehl werden Datei- und Verzeichnisrechte geändert.
Es gibt drei Arten von Rechten:
r: read (lesen)w: write (schreiben)x: execute (ausführen)
Man unterscheidet drei Benutzergruppen:
u: user (Besitzer)g: group (Gruppe)o: others (alle anderen)
a: all (alle drei Gruppen:u+g+o)
1.2 Schreibweisen
1.2.1 Symbolische Schreibweise
Es werden Buchstaben und Operatoren verwendet:
+: Recht hinzufügen-: Recht entfernen=: Rechte gleichsetzen
Beispiele:
chmod u+x datei.sh # Besitzer darf die Datei ausführen
chmod g-w datei.txt # Gruppe darf nicht mehr schreiben
chmod o=r datei.txt # Andere dürfen nur lesen
chmod a+r datei.txt # Alle dürfen lesen
1.2.2 Oktal-/Numerische Schreibweise
Jedes Recht hat einen Zahlenwert:
| Recht | Wert |
|---|---|
r | 4 |
w | 2 |
x | 1 |
Man addiert die Werte für jede Gruppe um Rechte zu setzen:
--- → 0+0+0 = 0 (keine Rechte)
--x → 0+0+1 = 1 (nur ausführen)
-w- → 0+2+0 = 2 (nur schreiben)
-wx → 0+2+1 = 3 (schreiben + ausführen)
r-- → 4+0+0 = 4 (nur lesen)
r-x → 4+0+1 = 5 (lesen + ausführen)
rw- → 4+2+0 = 6 (lesen + schreiben)
rwx → 4+2+1 = 7 (lesen + schreiben + ausführen)
Beispiel:
chmod 755 datei.sh
Bedeutung:
7(u) →rwx→ Besitzer darf alles5(g) →r-x→ Gruppe darf lesen & ausführen5(o) →r-x→ andere dürfen lesen & ausführen
1.3 Nützliche Operationen
-R → rekursiv (für Verzeichnisse):
chmod -R 755 /pfad/zum/verzeichnis
--reference=DATEI → Rechte von einer anderen Datei kopieren:
chmod --reference=vorlage.txt ziel.txt
-v → verbose, zeigt was geändert wurde:
chmod -v 644 datei.txt
2 chown
chown steht für change owner. Dieser Befehl ändern den Besitzer oder die Gruppe einer Datei bzw. eines Verzeichnisses.
Jede Datei hat
- einen
user(Besitzer) und - eine
group(Gruppe).
2.1 Syntax
chown [OPTIONEN] BESITZER[:GRUPPE] DATEI/VERZEICHNIS
BESITZER: neuer Benutzer, der die Datei besitzen sollGRUPPE: neue Gruppe, der die Datei angehören soll:→ trennt Besitzer und Gruppe
info
Nur Root oder der Besitzer selbst kann chown ausführen. Normale Nutzer können nicht einfach Dateien anderen Nutzern zuweisen. In dem Fall muss der Befehl mit Admin-Rechten ausgeführt werden:
sudo chown ...
Beispiele:
chown anna datei.txt # Ändert den Besitzer auf anna
chown :developers datei.txt # Ändert die Gruppe auf developers
chown anna:developers datei.txt # Ändert Besitzer auf anna und Gruppe auf developers
2.2 Wichtige Optionen
| Option | Bedeutung |
|---|---|
-R | rekursiv, für Verzeichnisse und deren Inhalte |
-v | verbose, zeigt Änderungen an |
--reference=DATEI | setzt Besitzer/Gruppe wie bei einer Referenzdatei |
Beispiel für Rekursiv:
chown -R anna:developers /home/anna/projekt
Alle Dateien und Unterverzeichnisse gehören danach dem Benutzer anna und der Gruppe developers.
Beispiel für --reference:
chown --reference=vorlage.txt ziel.txt
Besitzer & Gruppe wie bei vorlage.txt gesetzt.
note
Die Standardgruppe für normale Benutzer (nicht für Systemprozesse) lautet staff.
3 ACL
ACL steht für Access Control List (Zugriffssteuerungsliste). Sie erweitert das klassische UNIX-Berechtigungssystem (Lesen, Schreiben, Ausführen für Benutzer / Gruppe / andere) um feinere Zugriffsrechte.
Während das herkömmliche System nur drei Berechtigungsebenen kennt (z. B. rw-r--r--), kann eine ACL mehreren einzelnen Benutzern oder Gruppen ganz spezifische Rechte zuweisen.
note
ACLs sind eine erweiterte Form von Dateiberechtigungen, mit denen man mehr Kontrolle darüber hat, wer was mit einer Datei tun darf.
Beispiel:
Angenommen man hat die folgende Datei:
-rw-r--r-- user staff dokument.txt
Es darf nur user schreiben, alle anderen dürfen nur lesen. Mit einer ACL kann man z. B. einem zusätzlichen andern Benutzer wie john Schreibrechte geben:
chmod +a "alex allow write" dokument.txt
Der Befehl ls -le liefert dadurch die folgende Ausgabe:
-rw-r--r--+ user staff dokument.txt
0: john allow write
Das Pluszeichen (+) hinter den Berechtigungen zeigt an, dass eine ACL vorhanden ist.
3.1 Typische Befehle
| Befehl | Bedeutung |
|---|---|
ls -le | Zeigt ACL-Einträge für Dateien und Ordner |
chmod +a "user allow permission" | Fügt einen ACL-Eintrag hinzu |
chmod -a "user" | Entfernt einen ACL-Eintrag |
chmod -N datei | Entfernt alle ACLs von einer Datei |
Aliase, Pipes, Weiterleitungen und Verkettungen
1 Aliase
Ein Alias ist ein benutzerdefinierter Kurzbefehl. Er ersetzt längere und/oder häufig genutzt Terminal befehle durch ein Kürzel.
1.1 Typische Aliase (Beispiele)
alias ll="ls -lah"
alias la="ls -A"
alias gs="git status"
alias gp="git pull"
alias v="nvim"
alias ..="cd .."
alias ...="cd ../.."
Es sind auch dynamische Aliase möglich:
alias now='date "+%Y-%m-%d %H:%M:%S"'
alias weather='curl wttr.in'
1.2 Dauerhafte Speicherung von Aliasen
Damit die Aliase bei jedem Start verfügbar sind, müssen sie in die ~/.zshrc eingefügt werden (siehe auch Abschnitt “Die .zshrc-Datei”).
Öffnen von ~/.zshrc:
nano ~/.zshrc
Anschließend zum Beispiel:
# Eigene Aliase
alias editrc="nano ~/.zshrc"
alias reloadrc="source ~/.zshrc"
alias openfl="open -a ForkLift ."
Neuladen:
source ~/.zshrc
2 Pipes (|) – Kombination von Kommandos
Mit dem Pipe-Zeichen (|) wird die Ausgabe eines Befehls als Eingabe für den nächsten Befehl weitergeleitet. Auf diese Weise kann man kleine Werkzeuge zu sehr mächtigen Befehlen kombinieren.
2.1 Beispiele
Alle Dateien auflisten und nach Dateiendung .txt filtern:
ls | grep txt
ls: listet alle Dateien und Ordner im aktuellen Verzeichnis aufgrep txt: filtert die Ausgabe und zeigt nur Zeilen an, die „txt“ enthalten (d. h..txt-Dateien)
Prozesse anzeigen, die “Safari” enthalten:
ps aux | grep Safari
ps aux: zeigt alle laufenden Prozesse im System mit Benutzer, PID, CPU- und Speicherverbrauchgrep Safari: filtert die Prozessliste und zeigt nur Zeilen, in denen “Safari” vorkommt
Zählen, wie viele Zeilen im Log das Wort “ERROR” enthalten:
cat access.log | grep "ERROR" | wc -l
cat access.log: gibt den gesamten Inhalt der Dateiaccess.logausgrep "ERROR": filtert alle Zeilen, die das Wort „ERROR“ enthaltenwc -l: zählt die Anzahl der Zeilen der gefilterten Ausgabe (d. h. die Anzahl der Fehlermeldungen)
Pipes können beliebig verkettet werden. Somit sind sie in Kombination mit grep, awk, sed, sort, uniq, cut usw. sehr mächtig.
2.2 Relevante Befehle für Pipes
| Befehl | Beschreibung | Beispiel |
|---|---|---|
| grep | Filtert Zeilen nach Textmustern; unterstützt reguläre Ausdrücke | dmesg | grep error |
| awk | Verarbeitet Textzeilen spaltenweise, ermöglicht Filter, Formatierungen und erlaubt Berechnungen | ls -l | awk '{print $9, $5}' |
| sed | Stream-Editor zum Ersetzen und Bearbeiten von Text innerhalb eines Datenstroms | cat file.txt | sed 's/foo/bar/g' |
| sort | Sortiert Zeilen alphabetisch oder numerisch. | cat names.txt | sort |
| uniq | Entfernt doppelte Zeilen (oft nach sort verwendet) | sort file.txt | uniq |
| cut | Schneidet Spalten aus Textzeilen heraus (z. B. bei CSV-Dateien). | cat users.csv | cut -d',' -f1 |
2.2.1 grep
Durchsucht Textzeilen nach Mustern oder Wörtern. Unterstützt reguläre Ausdrücke.
Syntax:
grep [Optionen] Muster [Datei(en)]
Häufige Optionen:
-i: Groß-/Kleinschreibung ignorieren-r: rekursiv durchsuchen-n: Zeilennummern anzeigen
Beispiele:
grep "error" /var/log/system.log
ps aux | grep Safari
Siehe auch grep-Beispiele.
2.2.2 awk
Zeilen- und spaltenorientierter Textprozessor, ideal für Auswertungen oder Filterung.
Syntax:
awk '{Aktion}' [Datei]
Beispiele:
ls -l | awk '{print $9, $5}' # Dateiname + Größe
df -h | awk '{print $1, $5}' # Laufwerk + Auslastung
2.2.3 sed
Stream-Editor zum automatischen Bearbeiten von Texten in Datenströmen.
Syntax:
sed 's/ALT/NEU/g' [Datei]
Häufige Optionen:
-i: Änderungen direkt in der Datei speichern-n: unterdrückt Standardausgabe
Beispiele:
cat config.txt | sed 's/enabled=false/enabled=true/g'
sed -i '' 's/http:/https:/g' urls.txt
2.2.4 sort
Sortiert Zeilen alphabetisch oder numerisch.
Syntax:
sort [Optionen] [Datei]
Syntax:
-n: numerisch sortieren-r: Reihenfolge umkehren
Beispiele:
cat names.txt | sort
ls -l | sort -k5 -n
2.2.5 uniq
Entfernt aufeinanderfolgende Duplikate aus sortierten Listen.
Syntax:
uniq [Optionen] [Datei]
Häufige Optionen:
-c: zählt Vorkommen-d: zeigt nur doppelte Einträge
Beispiele:
sort names.txt | uniq
sort names.txt | uniq -c
2.2.6 cut
Extrahiert Spalten aus Textzeilen – besonders nützlich bei CSV-Dateien.
Syntax:
cut -d[Trennzeichen] -f[Feldnummer] [Datei]
Häufige Optionen:
-d: legt das Trennzeichen fest (z. B.,oder:)-f: bestimmt die Spaltennummer(n)
Beispiele:
cat users.csv | cut -d',' -f1 # erste Spalte (Name)
ps aux | cut -c1-10 # Zeichen 1–10 jeder Zeile
3 Weiterleitungen (>, >>, <)
Weiterleitungen bestimmen, wohin die Eingaben oder Ausgaben eines Befehls gehen.
3.1 Arten von Weiterleitungen
| Symbol | Bedeutung | Beispiel |
|---|---|---|
> | Ausgabe in Datei schreiben (überschreibt) | ls > dateien.txt |
>> | Ausgabe anhängen | echo "neuer Eintrag" >> log.txt |
< | Eingabe aus Datei lesen | sort < unsortiert.txt |
2> | Fehlermeldungen in Datei schreiben | ls xyz 2> fehler.txt |
&> | Ausgabe und Fehler umleiten | script.sh &> output.txt |
3.2 Beispiele
Die Namen aller JPEG-Dateien in eine Textdatei schreiben:
find . -name "*.jpg" > bilder.txt
Gefundene Warnungen aus einem Log an eine Textdatei anhängen:
grep "WARN" log.txt >> warnungen.txt
Aus input.txt lesen und in output.txt schreiben:
cat < input.txt > output.txt
Stumme Ausführung eines Befehls (keine Ausgabe, d. h. keine sichtbare Fehlermeldung):
befehl &> /dev/null
4 Verkettung von Befehlen – AND (&&) und OR (||)
mkdir ordner123 && cd ordner123 # Ordner erstellen und hineinwechseln
cd ordner123 || mkdir ordner123 # In Ordner wechseln oder erstellen, wenn er nicht existiert
Packetmanagement mit Homebrew
Das Software-Installationssystem Homebrew bezeichnet sich selbst als “The Missing Package Manager for macOS (or Linux)” und ist unter macOS der inoffizielle Standard für die Installation von Software über das Terminal. Homebrew macht die Kommandozeile zu einer echten Linux-ähnlichen Umgebung. Es verwaltet Programme, Bibliotheken und Entwicklerwerkzeuge – alles über einfache Befehle.
Installation von Homebrew:
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
Überprüfung, ob alles korrekt eingerichtet ist:
brew doctor
Wesentliche Vorteile von Homebrew:
- Sehr schnelle Installation von Software (deutlich schneller als manuell)
- Ermöglicht ein konsistentes Setup über mehrere Rechner hinweg
- Hat eine riesige Community und Tausende Pakete
1 Grundlegende Befehle
| Befehl | Beschreibung |
|---|---|
brew install <paket> | Installiert ein Paket |
brew uninstall <paket> | Entfernt ein Paket |
brew list | Zeigt installierte Pakete |
brew update | Aktualisiert Homebrew selbst |
brew upgrade | Aktualisiert installierte Pakete |
brew search <suchbegriff> | Sucht nach Paketen |
brew info <paket> | Zeigt Infos, Version, Pfad etc. |
brew cleanup | Löscht alte Versionen und Cache |
GUI-Apps über Homebrew Cask:
brew install --cask visual-studio-code
brew install --cask google-chrome
brew install --cask rectangle
--cask = für Anwendungen mit Benutzeroberfläche.
2 Paketpfade & Umgebungsvariablen
Homebrew installiert standardmäßig nach:
/usr/local(bei Intel-Macs)/opt/homebrew(bei Apple Silicon)
Über eine Umgebungsvariable in der ~/.zshrc kann man den Installationspfad anpassen:
export PATH="/opt/homebrew/bin:$PATH"
3 Backup und Wiederherstellung
Liste aller installierten Pakete erstellen:
brew bundle dump --file=~/brewfile.txt
Um die vorhandene Datei zu überschreiben:
brew bundle dump --file=~/brewfile.txt --force
Wiederherstellung der Installation:
brew bundle --file=~/brewfile.txt
4 Kombinationsbeispiel: Homebrew + Alias + Pipe
Auf veraltete Pakete prüfen:
alias brewoutdated="brew outdated | grep -vE 'python|node'"
Automatisches Aufräumen:
alias brewclean="brew cleanup && brew autoremove && brew doctor"
Tipps und Tools für maximale Effizienz
1 Kurzbefehle im Terminal
1.1 Navigation und Bearbeitung
| Kurzbefehl | Beschreibung |
|---|---|
| STRG + A | Springt zum Zeilenanfang |
| STRG + E | Springt zum Zeilenende |
| OPTION + B | Springt ein Wort zurück |
| OPTION + F | Springt ein Wort vorwärts |
| STRG + U | Löscht alles vor dem Cursor |
| STRG + K | Löscht alles nach dem Cursor |
| STRG + W | Löscht das Wort vor dem Cursor |
| OPTION + D | Löscht das Wort nach dem Cursor |
| STRG + Y | Fügt zuletzt gelöschten Text ein (yank) |
| STRG + L | Bildschirm löschen (wie clear) |
| STRG + C | Beendet den laufenden Prozess |
| STRG + Z | Hält den Prozess an (siehe Job-Control) |
| STRG + D | Beendet die Shell / EOF senden |
1.2 History-Navigation
| Kurzbefehl | Beschreibung |
|---|---|
| ↑ / ↓ | Vorherige/nächste Befehle durchsuchen |
| STRG + R | Rückwärts-Suche in der History |
| STRG + S | Vorwärts-Suche in der History |
| STRG + G | Suche abbrechen |
| !! | Letzten Befehl wiederholen |
| !$ | Letztes Argument des letzten Befehls |
| !^ | Erstes Argument des letzten Befehls |
| !* | Alle Argumente des letzten Befehls |
1.3 Tab-Vervollständigung
| Kurzbefehl | Beschreibung |
|---|---|
| TAB | Befehl/Pfad vervollständigen |
| TAB TAB | Alle Möglichkeiten anzeigen |
| OPTION + / | Pfad-Vervollständigung erzwingen |
1.4 Praktische Kombinationen
Letzten Befehl mit sudo wiederholen:
apt update
# Permission denied
sudo !!
Argument vom letzten Befehl übernehmen:
cat /etc/hosts
vim !$ # öffnet /etc/hosts in vim
In der History suchen:
# STRG + R drücken, dann tippen:
(reverse-i-search)`brew': brew install htop
2 Dokumentation
2.1 man – Handbuch zu beliebigem Befehl anzeigen
man grep
Navigation im Handbuch:
- Leertaste: Nächste Seite
b: Vorherige Seite/: Vorwärts suchen?: Rückwärts suchenn: Nächstes SuchergebnisN: Vorheriges Suchergebnisq: Beenden
Manpage-Sektionen:
man 1 printf # Benutzerkommandos
man 2 open # Systemaufrufe
man 3 printf # Bibliotheksfunktionen
2.2 whatis – Kurzbeschreibung
Zeigt eine einzeilige Beschreibung eines Befehls:
whatis ls
# ls(1) - list directory contents
whatis grep sed awk
# grep(1) - file pattern searcher
# sed(1) - stream editor
# awk(1) - pattern-directed scanning and processing language
2.3 apropos – Befehle suchen
Durchsucht die Manpage-Datenbank nach Stichwörtern:
apropos network
apropos "copy files"
apropos -s 1 search # Nur in Sektion 1 suchen
Nützlich, wenn man nicht genau weiß, welcher Befehl benötigt wird.
2.4 tldr – Vereinfachte Hilfe mit Beispielen
tldr (Too Long; Didn’t Read) bietet prägnante, praxisorientierte Hilfe mit Beispielen.
Installation:
brew install tldr
Verwendung:
tldr tar
tldr find
tldr git-commit
Beispielausgabe für tar:
tar
Archiving utility.
Often combined with a compression method, such as gzip or bzip2.
More information: https://www.gnu.org/software/tar.
- Create an archive from files:
tar cf target.tar file1 file2 file3
- Create a gzipped archive:
tar czf target.tar.gz file1 file2 file3
- Extract an archive:
tar xf source.tar
Cache aktualisieren:
tldr --update
2.5 Vergleich der Dokumentations-Tools
| Tool | Zweck | Detailgrad | Beispiele |
|---|---|---|---|
man | Vollständige Referenz | Sehr hoch | Wenige |
whatis | Kurzbeschreibung | Minimal | Keine |
apropos | Befehl finden | - | - |
tldr | Schnelle Hilfe | Mittel | Viele |
3 Empfohlener Workflow
- Unbekannter Befehl:
tldr <befehl>für schnelle Orientierung - Befehl finden:
apropos <stichwort>zum Suchen - Details nachschlagen:
man <befehl>für vollständige Dokumentation - Kurze Info:
whatis <befehl>für Einzeiler
4 Finder
Aktuellen Ordner oder ausgewählte Datei im Finder öffnen:
- Rechtsklick auf Ordner oder Datei in Pfadleiste :luc_arrow_right: “In Terminal öffnen”
- oder: Rechtsklick auf Ordner oder Datei in Pfadleiste :luc_arrow_right: “Dienste” :luc_arrow_right: “New Warp Tab Here”
5 tee-Befehl
Der tee-Befehl funktioniert als “T-Stück” für Datenströme. Er dupliziert die Ausgabe eines Befehls und sendet diese
- ins Terminal (
stdout) und - an eine andere Ziel (Datei, Pipe, usw.).
Dies ist besonders hilfreich bei Aliasen, Shell-Funktionen und Skripten.
Beispiel:
alias copypwd='pwd | tee >(pbcopy)'
Der aktuelle Pfad wird in die Zwischenablage kopiert und im Terminal ausgegeben. Mit pwd | pbcopy, d. h. ohne tee, wird nur der Pfad kopiert, aber nicht ausgegeben.
6 Ausführung von AppleScript
AppleScript- oder JXA-Code (JXA = JavaScript for Automation) kann mit dem Befehl osascript ausgeführt werden.
Syntax:
osascript [Optionen] [Datei | -e "Skript-Code"]
Ein Skript aus einer Datei ausführen:
osascript ~/Skripte/mein_skript.scpt
Beispiel:
Anzeige des Titels des aktuellen Songs aus Apple Music:
osascript -e 'tell application "Music" to get name of current track'
Optionen:
-
-e: Führe eine oder mehrere Codezeilen direkt aus. -
-l JavaScript: Verwende JavaScript statt AppleScriptBeispiel:
osascript -l JavaScript -e 'Application("Finder").open("/Applications")'
6.1 Mitteilungen
Mittels Apple Script ist es auch möglich, Mitteilungen, die rechts oben auf dem Bildschirm erscheinen, auszugeben:
osascript -e 'display notification "Hallo!"'
6.2 Typische Anwendungsfälle
- Automatisierung von Aufgaben von macOS-Apps (z. B. Fenster öffnen, Dateien verschieben)
- Systemdialoge oder Benachrichtigungen aus Skripten heraus anzeigen
- Kombination von Terminal-Befehle mit macOS-Funktionen (z. B. GUI-Interaktionen)
- Integration in Shell-Skripte und Workflows
7 Brace Expansion – Effiziente Musterbildung
Brace Expansion ist ein mächtiges Shell-Feature zum schnellen Erzeugen von Mustern und Sequenzen.
7.1 Zahlensequenzen
echo {1..10} # 1 2 3 4 5 6 7 8 9 10
echo {01..10} # 01 02 03 04 05 06 07 08 09 10
echo {10..1} # Rückwärts: 10 9 8 7 6 5 4 3 2 1
echo {a..z} # Buchstaben: a b c d ... z
echo {2..20..2} # Schrittweite: 2 4 6 8 10 12 14 16 18 20
7.2 Listen
echo {rot,grün,blau} # rot grün blau
mkdir {Docs,Images,Videos}
7.3 Kombinationen
echo {A,B}{1,2} # A1 A2 B1 B2
mkdir Jahr_{2023,2024}/{Q1,Q2,Q3,Q4}
7.4 Praktische Anwendungen
Backup erstellen:
cp wichtig.txt{,.backup} # Kopiert nach wichtig.txt.backup
Mehrere Dateien auf einmal umbenennen:
mv bild.{jpg,png} # Umbenennen von jpg zu png
Batch-Download:
curl https://example.com/file{001..100}.jpg -O
Projektstruktur anlegen:
mkdir -p projekt/{src,tests,docs}/{backend,frontend}
Beispiele für alltägliche Aufgaben im Terminal
1 Dateien suchen
Im aktuellen Ordner sollen alle Dateien vom Typ PDF gefunden werden.
1.1 GUI
- Finder öffnen :luc_arrow_right: im Eingabefeld für die Suche rechts oben “.pdf” eingeben
- Weitere Verfeinerungen über Filter möglich (
+-Button)
1.2 Terminal
find . -name "*.pdf"
:luc_arrow_right: Listet alle PDF-Dateien (auch in Unterordnern)
Bis hier ist der Aufwand gleich. Das Terminal ist jedoch deutlich schneller, wenn zusätzlich alle Dateien gefunden werden sollen, die einen bestimmten Dateiinhalt haben.
Beispiel:
find . -name "*.pdf" -exec grep -Hn "Rechnung" {} \
2 Zuletzt bearbeitete Dateien anzeigen
Es sollen alle JPEG-Dateien eines Ordners angezeigt werden, die in den letzten 10 Minuten bearbeitet wurden. Anschließend sollen diese in der Vorschau-App geöffnet werden.
2.1 GUI
- Im Finder in die Listenansicht wechseln und die Spalte “Änderungsdatum” anzeigen lassen, falls noch nicht vorhanden
- Auf die Spaltenüberschrift klicken, um nach Änderungsdatum zu sortieren
- Die Datei mit dem ältesten Änderungsdatum, das in Frage kommt, suchen
- Auswählen von dieser Datei und allen, die sich davor/dahinter befinden
- Rechtsklick :luc_arrow_right: Öffnen mit :luc_arrow_right: Vorschau.app
- Zurück zum Finder wechseln und alle ursprünglichen Darstellungseinstellungen wiederherstellen
2.2 Terminal
Alle JPEG-Dateien anzeigen, die nicht älter als 10 Minuten sind:
find . -type f -iname "*.jpeg" -mmin -10
Sollen Dateien mit den Endungen .jpg und .jpeg angezeigt werden, muss der Befehl wie folgt erweitert werden:
find . -type f \( -iname "*.jpg" -o -iname "*.jpeg" \) -mmin -10
Genau diese Dateien in der Vorschau-App öffnen:
find . -type f -iname "*.jpeg" -mmin -10 -print0 | xargs -0 open -a Preview
2.2.1 Alias
Besonders schnell und einfach erfolgt es, wenn man sich einen Alias erstellt:
alias showrecent='find . -type f -iname "*.jpg" -mmin $1'
Komfortabler ist es in diesem Fall, wenn man stattdessen Funktionen erstellt:
showrecent () {
echo "The following files were modified in the past $1 minutes:"
find . -type f -iname "*.*" -mmin -$1
}
openrecentjpg () {
echo "Opening the following files in preview:"
find . -type f \( -iname "*.jpg" -o -iname "*.jpeg" \) -mmin -$1
find . -type f \( -iname "*.jpg" -o -iname "*.jpeg" \) -mmin -$1 -print0 | xargs -0 open -a Preview
}
Verwendung:
showrecent 10
openrecentjpg 10
Beispielausgabe:
ls
IMG_7094.jpeg IMG_7096 Kopie.jpeg IMG_7097.jpeg IMG_7099.jpeg
IMG_7095.jpeg IMG_7096.jpeg IMG_7099 Kopie.jpeg
showrecent 10
The following files were modified in the past 10 minutes:
./IMG_7099 Kopie.jpeg
./IMG_7096 Kopie.jpeg
openrecentjpg 10
Opening the following files in preview:
./IMG_7099 Kopie.jpeg
./IMG_7096 Kopie.jpeg
tip
Sollte ein Funktionsname verwendet werden sollen, der zuvor ein Alias war (z. B. alias showrecent=... :luc_arrow_right: showrecent() ...) muss zuvor der folgende Befehl ausgeführt werden:
unalias <aliasname>
Shell-Scripting
1 Motivation & Abgrenzung: Shell-Scripting vs. Python
Auch wenn man Python beherrscht, lohnt es sich, Shell-Scripting zu lernen. Beide haben unterschiedliche Stärken und Einsatzzwecke und werden in der Praxis sehr häufig kombiniert, statt sich gegenseitig zu ersetzen.
Grundlegende Unterschiede:
| Thema | Shell-Scripting | Python |
|---|---|---|
| Zweck | Automatisierung von System- und Terminalaufgaben | Universelle Programmiersprache für komplexe Logik |
| Startzeit | Extrem schnell, sofort verfügbar | Interpreter-Start kostet mehr Zeit |
| Verfügbarkeit | Überall vorinstalliert (Unix, Linux, macOS) | Nicht immer vorinstalliert (abhängig vom System) |
| Datei- und Systemsteuerung | Sehr direkt, ideal für kleine Automatisierungen | Gut, aber oft umfangreichere Syntax/Module nötig |
| Textverarbeitung | Überragend durch sed, awk, grep, Pipes | Möglich, aber weniger kompakt |
| Komplexe Programme | Schwer wartbar bei großer Logik | Optimale Wahl für komplexe Software |
| Konfiguration / DevOps | Standard für Deployment, Cronjobs, Server-Skripte | Standard für Automatisierung, APIs, Datenverarbeitung |
2 was kann shell-scripting besser als python?
2.1 1. Schnelle Systembefehle und Administrative Tasks:
Beispiel: fünf Dateien verschieben und einen Dienst neu starten:
mv *.log /backup/logs && systemctl restart apache2
In Python ist es deutlich umständlicher:
import glob
import shutil
import subprocess
# Find all .log files
for file in glob.glob('*.log'):
shutil.move(file, '/backup/logs')
# Restart service
result = subprocess.run(
['systemctl', 'restart', 'apache2'], capture_output=True, text=True
)
if result.returncode == 0:
print('Service started.')
else:
print('Error: ', result.stderr)
Hier kann man klar sehen, dass Shell-Scripting bei einfachen Systemaufgaben schneller und präziser ist, während Python mehr Kontrolle und Fehlerbehandlung ermöglicht, aber auch mehr Code erfordert.
2.1.1 2. Pipelines und Stream-Verarbeitung:
Shell + Tools sind darauf optimiert, Streams zu verarbeiten, z. B.:
ps aux | grep python | awk '{print $2}' | xargs kill
In Python müsste man Prozesse einlesen, parsen, filtern, Subprozesse starten …
2.1.2 3. Automatisierung in Systemstart, Cron, Deployment:
- cronjobs
launchdsystemd- Installationsskripte (
install.shsind Standard)
2.1.3 4. Universelle Verfügbarkeit
Shell steht auf jedem Server bereit. Python nicht immer.
Shell-Scripting ist
- essentiell für DevOps, Sysadmins, Server & Deployment;
- perfekt für kleine Tools, Setup-Skripte und wiederkehrende Aufgaben;
- unverzichtbar für CI/CD & Cloud und
- enorm zeitsparend bei Routine-Aufgaben.
2.2 Was kann Python besser als Shell?
Python ist ideal für:
- komplexe Logik & Algorithmen
- APIs & Webservices
- Datenanalyse & Machine Learning
- GUI-Tools
- saubere Tests & Wartbarkeit
Beispiel: JSON-Parsing in Python:
import json
data = json.loads(json_string)
In Shell wäre das schwierig und fehleranfälliger. Es ist jq erforderlich (Kommandozeilenwerkzeug zur Verarbeitung von JSON-Daten).
2.3 Warum beides kombinieren?
Man muss sich nicht entscheiden: Häufig wird beides verwendet ⇒ Best-of-Both-Worlds.
Python aus einem Shell-Script heraus aufrufen:
#!/bin/zsh
echo "Starte Datenverarbeitung..."
python3 analyse.py input.csv
echo "Fertig!"
Shell aus Python heraus verwenden:
import subprocess
subprocess.run(["ls", "-la"])
Python als Tool + Shell als Wrapper (häufigste Variante):
#!/bin/zsh
INPUT=$1
python3 process.py "$INPUT" | tee results.txt
- Shell übernimmt Dateihandling und Prozesslogik
- Python rechnet, verarbeitet, analysiert
2.4 Zusammenfassung
Es ist wie ein Schraubendrehen vs. Akkuschrauber:
- Beides sind Werkzeuge.
- Shell = leicht, schnell, überall verfügbar
- Python = leistungsstark, modular, bei großen Aufgaben überlegen
Empfehlung:
- Shell für kleine Automatisierungen (10–50 Zeilen)
- Python für komplexe Logik, APIs, Datenverarbeitung, ML
- Beides kombinieren für professionelle DevOps-Workflows
3 Grundlagen des Shell-Scripting
Ein Shell-Skript ist eine Textdatei mit einer Folge von Befehlen, die nacheinander ausgeführt werden. Skripte ermöglichen die Automatisierung wiederkehrender Aufgaben und können beliebig komplex werden.
Minimales Beispiel:
#!/bin/zsh
echo "Hallo Welt"
3.1 Aliase vs. Funktionen
Sowohl Aliase als auch Funktionen dienen dazu, häufig verwendete Befehle abzukürzen. Sie unterscheiden sich jedoch in ihren Möglichkeiten.
Aliase:
Ein Alias ist eine einfache Textersetzung. Er eignet sich für kurze, statische Befehlsketten.
# Definition
alias ll="ls -lah"
alias gs="git status"
alias ..="cd .."
# Verwendung
ll
gs
..
Einschränkungen von Aliasen:
- Keine Argumente an beliebiger Stelle möglich
- Keine Kontrollstrukturen (
if,for,while) - Keine lokalen Variablen
# Das funktioniert NICHT wie erwartet:
alias greet="echo Hallo $1" # $1 wird sofort ausgewertet, nicht beim Aufruf
Funktionen:
Funktionen sind flexibler und ermöglichen komplexere Logik mit Argumenten, Variablen und Kontrollstrukturen.
# Definition
greet() {
echo "Hallo $1!"
}
# Verwendung
greet "Welt" # Ausgabe: Hallo Welt!
greet "Max" # Ausgabe: Hallo Max!
Beispiel mit mehreren Argumenten:
mkcd() {
mkdir -p "$1" && cd "$1"
}
# Verwendung
mkcd neuer_ordner # Erstellt Ordner und wechselt hinein
Beispiel mit Kontrollstruktur:
backup() {
if [-z "$1"](-z%20"$1".md); then
echo "Fehler: Kein Dateiname angegeben"
return 1
fi
cp "$1" "$1.bak"
echo "Backup erstellt: $1.bak"
}
Vergleich:
| Merkmal | Alias | Funktion |
|---|---|---|
| Argumente verarbeiten | ❌ Nein | ✅ Ja ($1, $2, …) |
| Kontrollstrukturen | ❌ Nein | ✅ Ja |
| Lokale Variablen | ❌ Nein | ✅ Ja (local) |
| Mehrzeilige Logik | ❌ Nein | ✅ Ja |
| Rückgabewerte | ❌ Nein | ✅ Ja (return) |
| Einfache Ersetzung | ✅ Ideal | Überdimensioniert |
Faustregel:
- Alias: Für einfache Abkürzungen ohne Argumente
- Funktion: Sobald Argumente, Logik oder Variablen benötigt werden
Speicherort:
Beide werden typischerweise in ~/.zshrc definiert. Bei vielen Aliasen und Funktionen empfiehlt sich eine Auslagerung:
# In ~/.zshrc
source ~/.config/zsh/aliases.zsh
source ~/.config/zsh/functions.zsh
Einbindung in .zshrc:
SCRIPT_DIR="/parent/folder/of/zshrc"
source "$SCRIPT_DIR/aliases.zsh"
source "$SCRIPT_DIR/functions.zsh"
4 Variablen
Variablen speichern Werte, die im Skript wiederverwendet werden können.
4.1 Variablenzuweisung
warning
Bei der Zuweisung von Werten, dürfen sich keine Leerzeichen um das = befinden!
# Richtig
name="Max"
zahl=42
pfad="/Users/max/Documents"
# FALSCH – führt zu Fehlern
name = "Max" # Fehler: "name" wird als Befehl interpretiert
Variablen verwenden:
name="Max"
echo "Hallo $name" # Ausgabe: Hallo Max
echo "Hallo ${name}!" # Ausgabe: Hallo Max!
echo "Pfad: ${name}_backup" # Geschweifte Klammern bei Verkettung
Befehlsausgabe in Variable speichern:
# Moderne Syntax (empfohlen)
datum=$(date +%Y-%m-%d)
dateien=$(ls -1 | wc -l)
# Alte Syntax (Backticks) – funktioniert, aber weniger lesbar
datum=`date +%Y-%m-%d`
echo "Heute ist $datum"
echo "Anzahl Dateien: $dateien"
Rechnen mit Variablen:
a=5
b=3
# Arithmetische Auswertung
summe=$((a + b))
produkt=$((a * b))
echo "Summe: $summe" # Ausgabe: Summe: 8
echo "Produkt: $produkt" # Ausgabe: Produkt: 15
4.2 Environment-Variablen vs. lokale Variablen
Lokale Variablen:
Lokale Variablen existieren nur in der aktuellen Shell oder Funktion. Sie werden nicht an Kindprozesse vererbt.
meine_var="lokal"
echo $meine_var # Funktioniert
# In einem Subprozess:
bash -c 'echo $meine_var' # Ausgabe: (leer)
Environment-Variablen (exportiert):
Mit export wird eine Variable zur Environment-Variable. Sie wird an alle Kindprozesse vererbt.
export MEINE_VAR="global"
echo $MEINE_VAR # Funktioniert
# In einem Subprozess:
bash -c 'echo $MEINE_VAR' # Ausgabe: global
Wichtige System-Environment-Variablen:
| Variable | Beschreibung |
|---|---|
$HOME | Home-Verzeichnis des Benutzers |
$PATH | Suchpfade für ausführbare Programme |
$USER | Aktueller Benutzername |
$SHELL | Pfad zur aktuellen Shell |
$PWD | Aktuelles Arbeitsverzeichnis |
$OLDPWD | Vorheriges Verzeichnis |
$EDITOR | Standard-Texteditor |
$LANG | Spracheinstellung |
Alle Environment-Variablen anzeigen:
env
printenv
Lokale Variablen in Funktionen:
Mit local wird eine Variable auf die Funktion beschränkt:
test_funktion() {
local lokale_var="nur hier sichtbar"
globale_var="überall sichtbar"
echo "In Funktion: $lokale_var"
}
test_funktion
echo "Außerhalb: $lokale_var" # Ausgabe: (leer)
echo "Außerhalb: $globale_var" # Ausgabe: überall sichtbar
5 Strings
5.1 Strings über mehrere Zeilen
Methode 1: Here-Document (heredoc):
cat << EOF
Dies ist ein mehrzeiliger Text.
Er kann Variablen enthalten: $USER
Und mehrere Zeilen umfassen.
EOF
In Variable speichern:
text=$(cat << EOF
Zeile 1
Zeile 2
Zeile 3
EOF
)
echo "$text"
Ohne Variablenexpansion (Anführungszeichen um EOF):
cat << 'EOF'
Hier wird $USER NICHT ersetzt.
Alles bleibt literal.
EOF
Methode 2: Anführungszeichen:
text="Zeile 1
Zeile 2
Zeile 3"
echo "$text"
Methode 3: String-Verkettung:
text="Zeile 1\n"
text+="Zeile 2\n"
text+="Zeile 3"
echo -e "$text" # -e interpretiert \n als Zeilenumbruch
5.2 String-Interpolation
Einfache Anführungszeichen vs. doppelte Anführungszeichen:
name="Max"
# Doppelte Anführungszeichen: Variablen werden ersetzt
echo "Hallo $name" # Ausgabe: Hallo Max
# Einfache Anführungszeichen: Alles literal
echo 'Hallo $name' # Ausgabe: Hallo $name
Geschweifte Klammern für Eindeutigkeit:
frucht="Apfel"
echo "$fruchtmus" # Fehler: Variable $fruchtmus existiert nicht
echo "${frucht}mus" # Korrekt: Apfelmus
Befehlssubstitution im String:
echo "Heute ist $(date +%A)" # Ausgabe: Heute ist Montag
echo "Es gibt $(ls | wc -l) Dateien" # Ausgabe: Es gibt 42 Dateien
Arithmetik im String:
echo "5 + 3 = $((5 + 3))" # Ausgabe: 5 + 3 = 8
String-Manipulationen in zsh:
text="Hallo Welt"
# Länge
echo ${#text} # Ausgabe: 10
# Substring (0-basiert)
echo ${text:0:5} # Ausgabe: Hallo
echo ${text:6} # Ausgabe: Welt
# Ersetzen
echo ${text/Welt/Max} # Ausgabe: Hallo Max
echo ${text//l/L} # Alle ersetzen: HaLLo WeLt
# Groß-/Kleinschreibung (zsh)
echo ${text:u} # Ausgabe: HALLO WELT
echo ${text:l} # Ausgabe: hallo welt
6 Argumente verarbeiten
Skripte und Funktionen können Argumente entgegennehmen, die beim Aufruf übergeben werden.
6.1 Zugriff über $1, $2 …
Die übergebenen Argumente sind über nummerierte Variablen zugänglich:
| Variable | Bedeutung |
|---|---|
$0 | Name des Skripts |
$1 | Erstes Argument |
$2 | Zweites Argument |
$3 … $9 | Weitere Argumente |
${10} | Ab 10: Geschweifte Klammern nötig |
$# | Anzahl der Argumente |
Beispiel:
#!/bin/zsh
# Datei: greet.sh
echo "Skriptname: $0"
echo "Erstes Argument: $1"
echo "Zweites Argument: $2"
echo "Anzahl Argumente: $#"
Aufruf:
./greet.sh Hallo Welt
# Ausgabe:
# Skriptname: ./greet.sh
# Erstes Argument: Hallo
# Zweites Argument: Welt
# Anzahl Argumente: 2
Prüfen ob Argument vorhanden:
#!/bin/zsh
if [-z "$1"](-z%20"$1".md); then
echo "Fehler: Kein Argument angegeben"
echo "Verwendung: $0 <name>"
exit 1
fi
echo "Hallo $1!"
6.2 $@ und $*
Beide repräsentieren alle übergebenen Argumente, verhalten sich aber unterschiedlich:
$@ – Jedes Argument separat (empfohlen):
#!/bin/zsh
# Datei: args.sh
echo "Mit \$@:"
for arg in "$@"; do
echo " Argument: '$arg'"
done
Aufruf:
./args.sh "Hallo Welt" foo bar
# Ausgabe:
# Argument: 'Hallo Welt'
# Argument: 'foo'
# Argument: 'bar'
$* – Alle Argumente als ein String:
#!/bin/zsh
echo "Mit \$*:"
for arg in "$*"; do
echo " Argument: '$arg'"
done
Aufruf:
./args.sh "Hallo Welt" foo bar
# Ausgabe:
# Argument: 'Hallo Welt foo bar'
Zusammenfassung:
| Syntax | Bedeutung |
|---|---|
"$@" | Jedes Argument als separates Wort (Leerzeichen in Argumenten bleiben erhalten) |
"$*" | Alle Argumente als ein einziger String |
$@ / $* | Ohne Anführungszeichen: Wörter werden bei Leerzeichen getrennt |
In der Regel wird "$@" verwendet.
Alle Argumente an anderen Befehl weitergeben:
#!/bin/zsh
# Wrapper-Skript
echo "Starte Programm mit allen Argumenten..."
/pfad/zum/programm "$@"
6.3 Optionen parsen (getopts)
Für Skripte mit Optionen (z. B. -v, -f datei) bietet getopts eine strukturierte Lösung.
Grundsyntax:
while getopts "vf:o:" opt; do
case $opt in
v) verbose=true ;;
f) input_file="$OPTARG" ;;
o) output_file="$OPTARG" ;;
?) echo "Ungültige Option"; exit 1 ;;
esac
done
Erklärung:
v– Option ohne Wert (Flag)f:– Option mit erforderlichem Wert (Doppelpunkt)$OPTARG– Enthält den Wert der Option
Vollständiges Beispiel:
#!/bin/zsh
# Datei: prozess.sh
# Standardwerte
verbose=false
input_file=""
output_file="output.txt"
# Hilfe-Funktion
show_help() {
echo "Verwendung: $0 [-v] [-f eingabe] [-o ausgabe]"
echo ""
echo "Optionen:"
echo " -v Ausführliche Ausgabe"
echo " -f DATEI Eingabedatei (erforderlich)"
echo " -o DATEI Ausgabedatei (Standard: output.txt)"
echo " -h Diese Hilfe anzeigen"
}
# Optionen parsen
while getopts "vf:o:h" opt; do
case $opt in
v) verbose=true ;;
f) input_file="$OPTARG" ;;
o) output_file="$OPTARG" ;;
h) show_help; exit 0 ;;
?) show_help; exit 1 ;;
esac
done
# Restliche Argumente (nach den Optionen)
shift $((OPTIND - 1))
remaining_args="$@"
# Validierung
if [-z "$input_file"](-z%20"$input_file".md); then
echo "Fehler: Eingabedatei erforderlich (-f)"
exit 1
fi
# Hauptlogik
if $verbose; then
echo "Eingabe: $input_file"
echo "Ausgabe: $output_file"
echo "Weitere Argumente: $remaining_args"
fi
echo "Verarbeite $input_file..."
Aufruf:
./prozess.sh -v -f input.txt -o result.txt zusatz1 zusatz2
7 Rückgabewerte und Exit-Codes
Jeder Befehl in Unix gibt einen Exit-Code zurück, der Erfolg oder Misserfolg signalisiert.
7.1 exit und $?
Exit-Codes:
| Code | Bedeutung |
|---|---|
0 | Erfolg |
1 | Allgemeiner Fehler |
2 | Falsche Verwendung (z. B. fehlende Argumente) |
126 | Befehl nicht ausführbar |
127 | Befehl nicht gefunden |
128+N | Beendet durch Signal N |
130 | Beendet durch Ctrl+C (SIGINT) |
$? – Exit-Code des letzten Befehls:
ls /existiert
echo $? # Ausgabe: 0 (Erfolg)
ls /existiert_nicht
echo $? # Ausgabe: 1 (Fehler)
exit in Skripten:
#!/bin/zsh
if [! -f "$1"](!%20-f%20"$1".md); then
echo "Fehler: Datei nicht gefunden"
exit 1
fi
echo "Datei gefunden"
exit 0
return in Funktionen:
Funktionen verwenden return statt exit:
pruefe_datei() {
if [-f "$1"](-f%20"$1".md); then
return 0 # Erfolg
else
return 1 # Fehler
fi
}
if pruefe_datei "test.txt"; then
echo "Datei existiert"
else
echo "Datei nicht gefunden"
fi
Exit-Code direkt in Bedingung:
if grep -q "suchbegriff" datei.txt; then
echo "Gefunden"
else
echo "Nicht gefunden"
fi
7.2 Fehlerbehandlung
Befehlsverkettung mit && und ||:
# && – Nächster Befehl nur bei Erfolg
mkdir neuer_ordner && cd neuer_ordner && echo "Erfolgreich"
# || – Nächster Befehl nur bei Fehler
cd /existiert_nicht || echo "Verzeichnis nicht gefunden"
# Kombination
cd /verzeichnis && echo "OK" || echo "Fehler"
Prüfung mit if:
#!/bin/zsh
if ! command -v git &> /dev/null; then
echo "Git ist nicht installiert"
exit 1
fi
echo "Git ist verfügbar"
Fehlerausgabe umleiten:
# Nur Fehler unterdrücken
befehl 2>/dev/null
# Alles unterdrücken
befehl &>/dev/null
# Fehler in Datei schreiben
befehl 2>> fehler.log
8 Ausführen und Debuggen
8.1 chmod +x
Bevor ein Skript direkt ausgeführt werden kann, muss es als ausführbar markiert werden:
# Ausführbar machen
chmod +x mein_skript.sh
# Ausführen
./mein_skript.sh
Alternativ ohne chmod:
zsh mein_skript.sh
bash mein_skript.sh
Berechtigungen prüfen:
ls -l mein_skript.sh
# -rwxr-xr-x 1 user staff 123 Jan 1 12:00 mein_skript.sh
# ^^^
# Die x's zeigen Ausführbarkeit an
8.2 set -x Debugging
Mit set -x wird jeder ausgeführte Befehl vor der Ausführung angezeigt:
#!/bin/zsh
set -x # Debug-Modus aktivieren
name="Max"
echo "Hallo $name"
datum=$(date)
echo "Datum: $datum"
Ausgabe:
+name=Max
+echo 'Hallo Max'
Hallo Max
+date
+datum='Mon Jan 1 12:00:00 CET 2024'
+echo 'Datum: Mon Jan 1 12:00:00 CET 2024'
Datum: Mon Jan 1 12:00:00 CET 2024
Debug-Modus ein-/ausschalten:
set -x # Aktivieren
# ... Debug-relevanter Code ...
set +x # Deaktivieren
Nur beim Aufruf aktivieren:
zsh -x mein_skript.sh
bash -x mein_skript.sh
8.3 Fehlerbehandlung (set -e, trap)
set -e – Bei Fehler abbrechen:
Standardmäßig läuft ein Skript weiter, auch wenn ein Befehl fehlschlägt. Mit set -e wird bei jedem Fehler abgebrochen:
#!/bin/zsh
set -e
echo "Schritt 1"
falsch_geschriebener_befehl # Skript bricht hier ab
echo "Schritt 2" # Wird nicht erreicht
set -u – Fehler bei undefinierten Variablen:
#!/bin/zsh
set -u
echo $undefinierte_variable # Skript bricht ab
set -o pipefail – Pipe-Fehler erkennen:
#!/bin/zsh
set -o pipefail
# Ohne pipefail: Exit-Code ist 0 (von wc)
# Mit pipefail: Exit-Code ist 1 (von cat)
cat nicht_vorhanden.txt | wc -l
Empfohlene Kombination:
#!/bin/zsh
set -euo pipefail
trap – Aufräumen bei Beendigung:
trap führt Befehle aus, wenn das Skript beendet wird (normal oder durch Fehler):
#!/bin/zsh
set -e
# Temporäre Datei erstellen
temp_file=$(mktemp)
echo "Temp-Datei: $temp_file"
# Bei Beendigung aufräumen
trap "rm -f $temp_file; echo 'Aufgeräumt'" EXIT
# Hauptlogik
echo "Arbeite..."
sleep 2
echo "Fertig"
# temp_file wird automatisch gelöscht
Verschiedene Signale abfangen:
#!/bin/zsh
cleanup() {
echo "Räume auf..."
# Aufräumarbeiten hier
}
trap cleanup EXIT # Bei normalem Ende
trap cleanup SIGINT # Bei Ctrl+C
trap cleanup SIGTERM # Bei kill
Praktisches Beispiel:
#!/bin/zsh
set -euo pipefail
# Temporäres Verzeichnis
work_dir=$(mktemp -d)
trap "rm -rf $work_dir" EXIT
echo "Arbeitsverzeichnis: $work_dir"
# Dateien im temp-Verzeichnis verarbeiten
cd "$work_dir"
curl -O https://example.com/datei.zip
unzip datei.zip
# ... weitere Verarbeitung ...
# work_dir wird automatisch gelöscht
8.4 Profiling (time, dtruss)
time – Ausführungszeit messen:
time ./mein_skript.sh
Ausgabe:
./mein_skript.sh 0.05s user 0.02s system 89% cpu 0.078 total
| Wert | Bedeutung |
|---|---|
user | CPU-Zeit im User-Mode |
system | CPU-Zeit im Kernel-Mode |
cpu | CPU-Auslastung in Prozent |
total | Gesamte verstrichene Zeit |
Einzelne Befehle messen:
time sleep 2
time find / -name "*.log" 2>/dev/null
dtruss – Systemaufrufe verfolgen (macOS):
dtruss ist das macOS-Äquivalent zu strace unter Linux. Es zeigt alle Systemaufrufe eines Prozesses:
# Erfordert Root-Rechte
sudo dtruss ./mein_skript.sh
Nur bestimmte Syscalls:
sudo dtruss -t open ./mein_skript.sh # Nur open()-Aufrufe
sudo dtruss -t read ./mein_skript.sh # Nur read()-Aufrufe
Laufenden Prozess analysieren:
sudo dtruss -p <PID>
Alternative: dtrace:
Für komplexere Analysen bietet macOS dtrace:
sudo dtrace -n 'syscall:::entry /execname == "zsh"/ { @[probefunc] = count(); }'
8.5 Shebang #!/bin/zsh
Die erste Zeile eines Skripts (Shebang) bestimmt, welcher Interpreter verwendet wird:
#!/bin/zsh
Häufige Shebangs:
| Shebang | Interpreter |
|---|---|
#!/bin/zsh | Z-Shell (macOS-Standard) |
#!/bin/bash | Bash |
#!/bin/sh | POSIX-Shell (portabel) |
#!/usr/bin/env zsh | zsh aus PATH (flexibler) |
#!/usr/bin/env python3 | Python 3 |
/usr/bin/env – Flexibler Ansatz:
#!/usr/bin/env zsh
Vorteile:
- Findet den Interpreter im
$PATH - Funktioniert auch wenn zsh nicht in
/bin/zshliegt - Portabler zwischen verschiedenen Systemen
Wichtig:
- Der Shebang muss in der ersten Zeile stehen
- Vor
#!dürfen keine Zeichen stehen (auch keine Leerzeichen) - Die Zeile muss mit einem Zeilenumbruch enden
9 Formatierung der Ausgabe
Insbesondere beim Schreiben von Aliasen, Funktionen und Skripten kann der Einsatz Farbe und Fettmarkierungen hilfreich sein, um die Ausgabe übersichtlich zu halten.
Beispiele:
echo "\033[31mRot\033[0m" # Rot
echo "\033[32mGrün\033[0m" # Grün
echo "\033[1;33mFett Gelb\033[0m" # Fetter Text
echo -e "\033[34m$(pwd)\033[0m" # Ausgabe von `pwd` in blau
\033[leitet eine Escape-Sequenz ein31= Rot,32= Grün,34= Blau1= Fett0m= Zurücksetzen der Formatierung
Häufig verwendete Farben:
| Code | Farbe | Stil |
|---|---|---|
30 | Schwarz | normal |
31 | Rot | normal |
32 | Grün | normal |
33 | Gelb | normal |
34 | Blau | normal |
35 | Magenta | normal |
36 | Cyan | normal |
37 | Weiß | normal |
Stile:
Erweiterte Stiltabelle:
| Code | Stil |
|---|---|
0 | Reset/Normal |
1 | Fett |
2 | Gedimmt |
3 | Kursiv |
4 | Unterstrichen |
5 | Blinkend |
7 | Invertiert |
9 | Durchgestrichen |
warning
Kursiv wird nicht von allen Terminals unterstützt. In manchen Terminals wird es als inverse Darstellung oder gar nicht angezeigt. Die meisten modernen Terminal-Emulatoren (iTerm2, Terminal.app ab neueren Versionen, etc.) unterstützen es jedoch.
10 Skript-Vorlage
#!/usr/bin/env zsh
set -euo pipefail
# [Short description of the script]
# --- Configuration ---
readonly SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
readonly SCRIPT_NAME="$(basename "$0")"
# --- Functions ---
show_help() {
cat << EOF
Usage: $SCRIPT_NAME [OPTIONS] <argument>
Description of the script.
Options:
-h, --help Show this help
Example:
$SCRIPT_NAME -v input.txt
EOF
}
log() { echo "[$(date '+%Y-%m-%d %H:%M:%S')] $*" }
# --- Main program ---
main() {
if [$]($.md#-eq-0); then
show_help
exit 1
fi
# Parse command line options
while getopts "h:" opt; do # Add further flags here
case $opt in
h) show_help; exit 0 ;;
\?) echo "Invalid option: -$OPTARG" >&2; exit 1 ;;
:) echo "Option -$OPTARG requires an argument" >&2; exit 1 ;;
esac
done
log "Script started"
# ... Main logic here ...
log "Script finished"
}
main "$@"
Regex, sed & awk
Reguläre Ausdrücke (Regex) sind ein mächtiges Werkzeug zur Mustererkennung in Texten. In Kombination mit sed und awk ermöglichen sie komplexe Textverarbeitung direkt im Terminal.
1 Regex-Grundlagen
Reguläre Ausdrücke beschreiben Suchmuster für Text. Sie werden von vielen Tools unterstützt: grep, sed, awk, find, vim und Programmiersprachen wie Python, JavaScript und Rust.
1.1 Literale Zeichen
Die einfachste Form: Zeichen matchen sich selbst.
echo "Hallo Welt" | grep "Welt" # Findet "Welt"
echo "Hallo Welt" | grep "xyz" # Keine Ausgabe
1.2 Metazeichen
Metazeichen haben eine besondere Bedeutung:
| Zeichen | Bedeutung | Beispiel | Matcht |
|---|---|---|---|
. | Beliebiges einzelnes Zeichen | H.llo | Hallo, Hello, H2llo |
^ | Zeilenanfang | ^Hallo | “Hallo” am Anfang |
$ | Zeilenende | Welt$ | “Welt” am Ende |
* | 0 oder mehr des vorherigen | ab*c | ac, abc, abbc, abbbc |
+ | 1 oder mehr des vorherigen | ab+c | abc, abbc (nicht ac) |
? | 0 oder 1 des vorherigen | colou?r | color, colour |
\ | Escapen von Metazeichen | \. | Literaler Punkt |
Beispiele:
# Zeilen die mit "Error" beginnen
grep "^Error" logfile.txt
# Zeilen die mit ".txt" enden
grep "\.txt$" dateiliste.txt
# Beliebiges Zeichen zwischen H und llo
echo -e "Hallo\nHello\nHullo" | grep "H.llo"
1.3 Zeichenklassen
Zeichenklassen matchen eines von mehreren Zeichen:
| Syntax | Bedeutung | Beispiel |
|---|---|---|
[abc] | a, b oder c | [Hh]allo matcht “Hallo” und “hallo” |
[^abc] | Nicht a, b oder c | [^0-9] matcht Nicht-Ziffern |
[a-z] | Kleinbuchstaben a–z | [a-zA-Z] alle Buchstaben |
[0-9] | Ziffern 0–9 | [0-9]+ eine oder mehr Ziffern |
Vordefinierte Zeichenklassen (POSIX):
| Klasse | Bedeutung | Äquivalent |
|---|---|---|
[:alpha:](:alpha:.md) | Buchstaben | [a-zA-Z] |
[:digit:](:digit:.md) | Ziffern | [0-9] |
[:alnum:](:alnum:.md) | Buchstaben und Ziffern | [a-zA-Z0-9] |
[:space:](:space:.md) | Whitespace | [ \t\n\r] |
[:upper:](:upper:.md) | Großbuchstaben | [A-Z] |
[:lower:](:lower:.md) | Kleinbuchstaben | [a-z] |
[:punct:](:punct:.md) | Satzzeichen | [.,!?;:] etc. |
Beispiele:
# Nur Zeilen mit Ziffern
grep "[0-9]" datei.txt
# Zeilen die mit Großbuchstaben beginnen
grep "^[A-Z]" datei.txt
# Wörter mit Bindestrich
grep "[a-z]-[a-z]" datei.txt
1.4 Quantifizierer
Quantifizierer bestimmen, wie oft ein Element vorkommen darf:
| Syntax | Bedeutung | Beispiel |
|---|---|---|
* | 0 oder mehr | a* matcht “”, a, aa, aaa |
+ | 1 oder mehr | a+ matcht a, aa, aaa (nicht “”) |
? | 0 oder 1 | a? matcht “”, a |
{n} | Genau n-mal | a{3} matcht aaa |
{n,} | Mindestens n-mal | a{2,} matcht aa, aaa, aaaa |
{n,m} | n bis m-mal | a{2,4} matcht aa, aaa, aaaa |
Beispiele:
# Telefonnummern (vereinfacht)
grep -E "[0-9]{3,5}" kontakte.txt
# Postleitzahlen (5 Ziffern)
grep -E "^[0-9]{5}$" plz.txt
# Optionaler Bindestrich
grep -E "[0-9]{4}-?[0-9]{4}" nummern.txt
1.5 Gruppen und Alternativen
| Syntax | Bedeutung | Beispiel |
|---|---|---|
(...) | Gruppierung | (ab)+ matcht ab, abab, ababab |
| | Alternative (ODER) | cat|dog matcht cat oder dog |
\1, \2 | Rückreferenz | (.)\1 matcht aa, bb, cc (Dopplungen) |
Beispiele:
# "error" oder "warning" (case-insensitive)
grep -iE "(error|warning)" logfile.txt
# Wiederholte Wörter finden
grep -E "\b(\w+)\s+\1\b" text.txt
# Entweder http oder https
grep -E "https?://" urls.txt
1.6 Anker und Wortgrenzen
| Syntax | Bedeutung |
|---|---|
^ | Zeilenanfang |
$ | Zeilenende |
\b | Wortgrenze |
\B | Keine Wortgrenze |
\< | Wortanfang |
\> | Wortende |
Beispiele:
# Nur das Wort "the" (nicht "there", "other")
grep -E "\bthe\b" text.txt
# Zeilen die nur aus Ziffern bestehen
grep -E "^[0-9]+$" datei.txt
# Leere Zeilen
grep -E "^$" datei.txt
1.7 BRE vs. ERE
Es gibt zwei Regex-Varianten:
BRE (Basic Regular Expressions):
- Standard bei
grepundsed +,?,|,()müssen escaped werden:\+,\?,\|,\(\)
ERE (Extended Regular Expressions):
- Bei
grep -E(oderegrep) undsed -E +,?,|,()funktionieren direkt
# BRE: Escaping nötig
grep "https\?" urls.txt
sed 's/\(error\|warning\)/PROBLEM/g' log.txt
# ERE: Kein Escaping
grep -E "https?" urls.txt
sed -E 's/(error|warning)/PROBLEM/g' log.txt
Empfehlung: ERE verwenden (grep -E, sed -E) für bessere Lesbarkeit.
1.8 Regex-Schnellreferenz
Zeichen:
. Beliebiges Zeichen
\d Ziffer (manche Tools)
\w Wortzeichen [a-zA-Z0-9_]
\s Whitespace
Anker:
^ Zeilenanfang
$ Zeilenende
\b Wortgrenze
Quantifizierer:
* 0 oder mehr
+ 1 oder mehr
? 0 oder 1
{n} Genau n
{n,m} n bis m
Klassen:
[abc] a, b oder c
[^abc] Nicht a, b, c
[a-z] Bereich a bis z
Gruppen:
(...) Gruppe
| Alternative
\1 Rückreferenz
2 sed – Stream Editor
sed (Stream Editor) verarbeitet Text zeilenweise und führt Transformationen durch. Es ist ideal für automatisierte Ersetzungen und Textmanipulationen.
2.1 Grundsyntax
sed [OPTIONEN] 'BEFEHL' [DATEI]
Häufige Optionen:
| Option | Bedeutung |
|---|---|
-i | In-place: Datei direkt ändern |
-i '' | In-place ohne Backup (macOS) |
-i.bak | In-place mit Backup |
-E | Extended Regex (ERE) |
-n | Keine automatische Ausgabe |
2.2 Suchen und Ersetzen (s)
Das häufigste sed-Kommando:
sed 's/SUCHE/ERSETZUNG/FLAGS'
Flags:
| Flag | Bedeutung |
|---|---|
g | Global: Alle Vorkommen ersetzen |
i | Case-insensitive |
p | Zeile ausgeben (mit -n) |
1, 2, … | Nur n-tes Vorkommen ersetzen |
Beispiele:
# Erstes Vorkommen pro Zeile
echo "hallo hallo" | sed 's/hallo/hi/'
# Ausgabe: hi hallo
# Alle Vorkommen
echo "hallo hallo" | sed 's/hallo/hi/g'
# Ausgabe: hi hi
# Case-insensitive
echo "Hallo HALLO" | sed 's/hallo/hi/gi'
# Ausgabe: hi hi
# Nur zweites Vorkommen
echo "a a a a" | sed 's/a/X/2'
# Ausgabe: a X a a
2.3 Trennzeichen
Das Trennzeichen muss nicht / sein – nützlich bei Pfaden:
# Mit /
sed 's/\/usr\/local/\/opt/g'
# Besser: Anderes Trennzeichen
sed 's|/usr/local|/opt|g'
sed 's#/usr/local#/opt#g'
sed 's@/usr/local@/opt@g'
2.4 Gruppen und Rückreferenzen
Mit \(...\) (BRE) oder (...) (ERE) können Teile erfasst und mit \1, \2 wiederverwendet werden:
# Reihenfolge tauschen
echo "Max Mustermann" | sed -E 's/([^ ]+) ([^ ]+)/\2, \1/'
# Ausgabe: Mustermann, Max
# Datum umformatieren
echo "2024-01-15" | sed -E 's/([0-9]{4})-([0-9]{2})-([0-9]{2})/\3.\2.\1/'
# Ausgabe: 15.01.2024
# Wörter verdoppeln
echo "test" | sed -E 's/(.+)/\1 \1/'
# Ausgabe: test test
# HTML-Tags entfernen
echo "<b>Text</b>" | sed -E 's/<[^>]+>//g'
# Ausgabe: Text
2.5 Adressierung – Zeilen auswählen
Befehle können auf bestimmte Zeilen beschränkt werden:
| Adresse | Bedeutung |
|---|---|
5 | Nur Zeile 5 |
5,10 | Zeilen 5 bis 10 |
$ | Letzte Zeile |
/muster/ | Zeilen die Muster enthalten |
1,/muster/ | Von Zeile 1 bis erste Zeile mit Muster |
Beispiele:
# Nur Zeile 3 bearbeiten
sed '3s/alt/neu/' datei.txt
# Zeilen 2-5 bearbeiten
sed '2,5s/alt/neu/' datei.txt
# Letzte Zeile bearbeiten
sed '$s/alt/neu/' datei.txt
# Nur Zeilen mit "error"
sed '/error/s/status/STATUS/' log.txt
# Ab "START" bis "END"
sed '/START/,/END/s/foo/bar/g' datei.txt
2.6 Weitere sed-Befehle
| Befehl | Bedeutung |
|---|---|
d | Zeile löschen |
p | Zeile ausgeben |
a\TEXT | Text nach Zeile einfügen |
i\TEXT | Text vor Zeile einfügen |
c\TEXT | Zeile ersetzen |
y/abc/xyz/ | Zeichen transliterieren |
Beispiele:
# Zeilen löschen
sed '3d' datei.txt # Zeile 3 löschen
sed '/^#/d' config.txt # Kommentare löschen
sed '/^$/d' datei.txt # Leere Zeilen löschen
# Zeilen ausgeben (mit -n)
sed -n '5p' datei.txt # Nur Zeile 5 ausgeben
sed -n '10,20p' datei.txt # Zeilen 10-20
sed -n '/error/p' log.txt # Nur Zeilen mit "error"
# Text einfügen
sed '3a\Neue Zeile' datei.txt # Nach Zeile 3
sed '1i\Kopfzeile' datei.txt # Vor Zeile 1
# Zeichen ersetzen (wie tr)
echo "hello" | sed 'y/aeiou/AEIOU/'
# Ausgabe: hEllO
2.7 Mehrere Befehle
# Mit -e
sed -e 's/foo/bar/' -e 's/baz/qux/' datei.txt
# Mit Semikolon
sed 's/foo/bar/; s/baz/qux/' datei.txt
# Mehrzeilig
sed '
s/foo/bar/g
s/baz/qux/g
/^#/d
' datei.txt
2.8 In-place-Bearbeitung
# macOS: Leeres Backup-Suffix erforderlich
sed -i '' 's/alt/neu/g' datei.txt
# Mit Backup
sed -i '.bak' 's/alt/neu/g' datei.txt
# Linux: Kein Suffix nötig
sed -i 's/alt/neu/g' datei.txt
2.9 Praktische sed-Beispiele
# Leerzeichen am Zeilenende entfernen
sed 's/[:space:](:space:.md)*$//' datei.txt
# Mehrere Leerzeichen zu einem
sed -E 's/ +/ /g' datei.txt
# Erste Zeile jeder Datei (wie head -1)
sed -n '1p' *.txt
# Zeilen 5-10 löschen
sed '5,10d' datei.txt
# Jede Zeile nummerieren
sed = datei.txt | sed 'N; s/\n/\t/'
# Zwischen zwei Markern ersetzen
sed '/BEGIN/,/END/s/old/new/g' datei.txt
# Konfigurationswert ändern
sed -E 's/^(port=).*/\18080/' config.txt
# CSV: Spaltenreihenfolge ändern
sed -E 's/([^,]+),([^,]+),([^,]+)/\3,\1,\2/' data.csv
3 awk – Textanalyse und Berichte
awk ist eine vollständige Programmiersprache für Textverarbeitung. Es eignet sich besonders für spaltenbasierte Daten wie CSV, Logs und tabellarische Ausgaben.
3.1 Grundsyntax
awk [OPTIONEN] 'PROGRAMM' [DATEI]
Ein awk-Programm besteht aus Regeln:
MUSTER { AKTION }
- Zeilen die dem MUSTER entsprechen, führen die AKTION aus
- Ohne MUSTER: Aktion auf alle Zeilen
- Ohne AKTION: Zeile ausgeben
3.2 Felder und Variablen
awk teilt jede Zeile automatisch in Felder:
| Variable | Bedeutung |
|---|---|
$0 | Gesamte Zeile |
$1 | Erstes Feld |
$2 | Zweites Feld |
$NF | Letztes Feld |
$(NF-1) | Vorletztes Feld |
NF | Anzahl der Felder |
NR | Aktuelle Zeilennummer |
FNR | Zeilennummer in aktueller Datei |
FS | Feldtrenner (Standard: Whitespace) |
OFS | Ausgabe-Feldtrenner |
RS | Zeilentrenner |
ORS | Ausgabe-Zeilentrenner |
Beispiele:
# Erste Spalte ausgeben
echo "Max 30 Berlin" | awk '{print $1}'
# Ausgabe: Max
# Mehrere Spalten
echo "Max 30 Berlin" | awk '{print $1, $3}'
# Ausgabe: Max Berlin
# Spalten in anderer Reihenfolge
echo "Max 30 Berlin" | awk '{print $3, $1, $2}'
# Ausgabe: Berlin Max 30
# Letzte Spalte
echo "a b c d e" | awk '{print $NF}'
# Ausgabe: e
# Anzahl Felder
echo "a b c d e" | awk '{print NF}'
# Ausgabe: 5
3.3 Feldtrenner ändern
# Mit -F
awk -F',' '{print $1}' datei.csv
awk -F':' '{print $1, $3}' /etc/passwd
# Im Programm
awk 'BEGIN{FS=","} {print $1}' datei.csv
# Mehrere Trennzeichen
awk -F'[,;:]' '{print $1}' datei.txt
# Tab als Trenner
awk -F'\t' '{print $2}' datei.tsv
3.4 Muster (Pattern)
# Zeilen mit "error"
awk '/error/' log.txt
# Zeilen die NICHT "comment" enthalten
awk '!/comment/' datei.txt
# Zeilen wo Feld 3 größer als 100
awk '$3 > 100' daten.txt
# Zeilen wo Feld 1 einem Muster entspricht
awk '$1 ~ /^A/' namen.txt
# Kombination
awk '/error/ && $3 > 5' log.txt
# Bereichsmuster
awk '/START/,/END/' datei.txt
3.5 BEGIN und END
BEGIN wird vor der ersten Zeile ausgeführt, END nach der letzten:
# Kopfzeile ausgeben
awk 'BEGIN{print "Name\tAlter"} {print $1, $2}' daten.txt
# Summe berechnen
awk '{sum += $1} END{print "Summe:", sum}' zahlen.txt
# Zeilen zählen
awk 'END{print NR, "Zeilen"}' datei.txt
# Durchschnitt berechnen
awk '{sum += $1; count++} END{print "Durchschnitt:", sum/count}' zahlen.txt
3.6 Formatierte Ausgabe mit printf
# Grundsyntax
awk '{printf "%-10s %5d\n", $1, $2}' daten.txt
Format-Spezifizierer:
| Format | Bedeutung |
|---|---|
%s | String |
%d | Integer |
%f | Fließkommazahl |
%.2f | 2 Dezimalstellen |
%10s | 10 Zeichen breit, rechtsbündig |
%-10s | 10 Zeichen breit, linksbündig |
Beispiele:
# Tabelle formatieren
awk '{printf "%-15s %8.2f\n", $1, $2}' preise.txt
# Mit Kopfzeile
awk 'BEGIN{printf "%-15s %8s\n", "Produkt", "Preis"; print "------------------------"}
{printf "%-15s %8.2f\n", $1, $2}' preise.txt
3.7 Variablen und Berechnungen
# Eigene Variablen
awk '{total = $2 * $3; print $1, total}' bestellung.txt
# Externe Variablen übergeben
threshold=100
awk -v limit="$threshold" '$2 > limit {print}' daten.txt
# Mehrere Variablen
awk -v min=10 -v max=50 '$1 >= min && $1 <= max' zahlen.txt
3.8 Kontrollstrukturen
if-else:
awk '{
if ($3 > 100)
print $1, "hoch"
else if ($3 > 50)
print $1, "mittel"
else
print $1, "niedrig"
}' daten.txt
for-Schleife:
# Alle Felder ausgeben
awk '{for(i=1; i<=NF; i++) print i, $i}' datei.txt
# Felder rückwärts
awk '{for(i=NF; i>=1; i--) printf "%s ", $i; print ""}' datei.txt
while-Schleife:
awk '{
i = 1
while(i <= NF) {
print $i
i++
}
}' datei.txt
3.9 Arrays
# Werte zählen
awk '{count[$1]++} END{for(key in count) print key, count[key]}' log.txt
# Summen nach Kategorie
awk '{sum[$1] += $2} END{for(cat in sum) print cat, sum[cat]}' verkauf.txt
# Duplikate finden
awk 'seen[$0]++' datei.txt
# Einzigartige Zeilen (wie uniq)
awk '!seen[$0]++' datei.txt
3.10 Eingebaute Funktionen
String-Funktionen:
| Funktion | Bedeutung |
|---|---|
length(s) | Länge des Strings |
substr(s,i,n) | Substring ab Position i, n Zeichen |
index(s,t) | Position von t in s |
split(s,a,fs) | String in Array aufteilen |
sub(r,s) | Erstes Vorkommen ersetzen |
gsub(r,s) | Alle Vorkommen ersetzen |
tolower(s) | In Kleinbuchstaben |
toupper(s) | In Großbuchstaben |
Beispiele:
# Stringlänge
echo "Hallo Welt" | awk '{print length($0)}'
# Ausgabe: 10
# Substring
echo "Hallo Welt" | awk '{print substr($0, 1, 5)}'
# Ausgabe: Hallo
# Ersetzen
echo "foo bar foo" | awk '{gsub(/foo/, "baz"); print}'
# Ausgabe: baz bar baz
# Großbuchstaben
echo "hallo" | awk '{print toupper($0)}'
# Ausgabe: HALLO
Mathematische Funktionen:
| Funktion | Bedeutung |
|---|---|
int(x) | Ganzzahliger Anteil |
sqrt(x) | Quadratwurzel |
sin(x), cos(x) | Trigonometrische Funktionen |
log(x) | Natürlicher Logarithmus |
exp(x) | e^x |
rand() | Zufallszahl 0–1 |
3.11 Praktische awk-Beispiele
# CSV: Bestimmte Spalten extrahieren
awk -F',' '{print $1, $3}' data.csv
# Summe einer Spalte
awk '{sum += $2} END{print sum}' zahlen.txt
# Durchschnitt
awk '{sum += $1; n++} END{print sum/n}' zahlen.txt
# Maximum finden
awk 'BEGIN{max=0} $1>max{max=$1} END{print max}' zahlen.txt
# Zeilen mit mehr als 3 Feldern
awk 'NF > 3' datei.txt
# Jede zweite Zeile
awk 'NR % 2 == 0' datei.txt
# Zeilen zwischen zwei Markern (ohne Marker)
awk '/START/{flag=1; next} /END/{flag=0} flag' datei.txt
# IP-Adressen extrahieren aus Log
awk '{print $1}' access.log | sort | uniq -c | sort -rn | head
# Dateigröße pro Verzeichnis
ls -l | awk '/^-/{sum += $5} END{print "Total:", sum, "Bytes"}'
# Spalten vertauschen
awk '{print $2, $1, $3}' datei.txt
# Bestimmte Zeilen und Spalten
awk 'NR >= 5 && NR <= 10 {print $1, $3}' datei.txt
# Feldtrenner für Ausgabe setzen
awk 'BEGIN{OFS=","} {print $1, $2, $3}' datei.txt
# Top 10 häufigste Werte
awk '{print $1}' datei.txt | sort | uniq -c | sort -rn | head -10
4 Kombinationsbeispiele (Pipe-Workflows)
Die wahre Stärke von sed, awk und Regex zeigt sich in Kombination mit anderen Unix-Tools.
4.1 Log-Analyse
Fehler aus Log extrahieren und zählen:
grep -i "error" application.log | \
awk '{print $4}' | \
sort | uniq -c | sort -rn | head -10
Zugriffe pro Stunde aus Access-Log:
awk '{print $4}' access.log | \
cut -d: -f2 | \
sort | uniq -c | \
awk '{print $2":00", $1}'
IP-Adressen mit den meisten Fehlern:
grep " 404 \| 500 " access.log | \
awk '{print $1}' | \
sort | uniq -c | sort -rn | head -10
Langsame Requests finden (> 5 Sekunden):
awk '$NF > 5000 {print $7, $NF"ms"}' access.log | \
sort -t' ' -k2 -rn | head -20
4.2 Dateitransformationen
CSV zu TSV konvertieren:
sed 's/,/\t/g' data.csv > data.tsv
JSON-Lines zu CSV (einfach):
cat data.jsonl | \
sed 's/[{}":]//g' | \
sed 's/,/\t/g'
Konfigurationsdatei bereinigen:
# Kommentare und leere Zeilen entfernen, sortieren
grep -v '^#' config.txt | \
grep -v '^$' | \
sed 's/[:space:](:space:.md)*$//' | \
sort
Markdown-Überschriften extrahieren:
grep -E "^#{1,3} " document.md | \
sed 's/^#* //' | \
awk '{printf "%d. %s\n", NR, $0}'
4.3 System-Administration
Disk-Usage sortiert nach Größe:
du -sh * 2>/dev/null | \
sort -rh | head -20
Größte Dateien finden:
find . -type f -exec ls -la {} \; 2>/dev/null | \
awk '{print $5, $9}' | \
sort -rn | head -20
Prozesse nach Memory-Verbrauch:
ps aux | \
awk 'NR>1 {print $4, $11}' | \
sort -rn | head -10
Offene Ports auflisten:
netstat -an | \
grep LISTEN | \
awk '{print $4}' | \
sed 's/.*\.//' | \
sort -n | uniq
4.4 Textbereinigung
Mehrfache Leerzeichen und -zeilen bereinigen:
cat messy.txt | \
sed 's/[:space:](:space:.md)\+/ /g' | \
sed 's/^[:space:](:space:.md)//' | \
sed 's/[:space:](:space:.md)$//' | \
cat -s
HTML-Tags entfernen:
sed -E 's/<[^>]+>//g' page.html | \
sed '/^$/d' | \
sed 's/ / /g; s/&/\&/g; s/</</g; s/>/>/g'
E-Mail-Adressen extrahieren:
grep -oE '[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}' dokument.txt | \
sort -u
URLs extrahieren:
grep -oE 'https?://[^[:space:]"<>]+' webpage.html | \
sort -u
4.5 Datenanalyse
CSV-Statistiken:
# Spalte 3: Min, Max, Durchschnitt
awk -F',' 'NR>1 {
sum += $3; count++;
if(min == "" || $3 < min) min = $3;
if(max == "" || $3 > max) max = $3
} END {
print "Min:", min
print "Max:", max
print "Avg:", sum/count
}' data.csv
Häufigkeit von Werten in Spalte:
awk -F',' 'NR>1 {count[$2]++} END {
for(val in count) print count[val], val
}' data.csv | sort -rn
Gruppierte Summen:
awk -F',' 'NR>1 {sum[$1] += $3} END {
for(group in sum) print group, sum[group]
}' sales.csv | sort -t' ' -k2 -rn
4.6 Batch-Umbenennung
Dateinamen bereinigen (Leerzeichen durch Unterstriche):
for f in *\ *; do
mv "$f" "$(echo $f | sed 's/ /_/g')"
done
Dateien mit Datum versehen:
for f in *.txt; do
mv "$f" "$(date +%Y%m%d)_$f"
done
Erweiterung ändern:
for f in *.jpeg; do
mv "$f" "${f%.jpeg}.jpg"
done
# Oder mit sed
ls *.jpeg | sed 's/\(.*\)\.jpeg/mv "\1.jpeg" "\1.jpg"/' | sh
4.7 Komplexe Pipeline-Beispiele
Git: Änderungen pro Autor (letzte 30 Tage):
git log --since="30 days ago" --format='%an' | \
sort | uniq -c | sort -rn
Apache-Log: Requests pro Minute visualisieren:
awk '{print $4}' access.log | \
cut -d: -f1-3 | \
uniq -c | \
awk '{printf "%s %s\n", $2, substr("====================", 1, $1/10)}'
Wort-Frequenz-Analyse:
cat text.txt | \
tr '[:upper:]' '[:lower:]' | \
tr -cs '[:alpha:]' '\n' | \
sort | uniq -c | sort -rn | head -20
JSON-Werte aggregieren (mit jq und awk):
cat data.json | \
jq -r '.[] | "\(.category) \(.amount)"' | \
awk '{sum[$1] += $2} END {for(c in sum) print c, sum[c]}' | \
sort -k2 -rn
4.8 Debugging von Pipelines
Schritt-für-Schritt testen:
# Erst einzeln testen
cat log.txt | head
cat log.txt | grep "error" | head
cat log.txt | grep "error" | awk '{print $1}' | head
# ... dann erweitern
Zwischenergebnisse mit tee:
cat data.txt | \
tee /dev/stderr | \ # Zeigt Zwischenergebnis
grep "pattern" | \
tee step1.txt | \ # Speichert Zwischenergebnis
awk '{print $2}'
Pipeline mit Zeilennummern debuggen:
cat -n datei.txt | grep "muster"
Cronjobs & launchd
Automatisierte Aufgaben sind essentiell für Systemadministration, Backups, Wartung und wiederkehrende Prozesse. Unter macOS gibt es zwei Systeme: das klassische Unix-Tool cron und Apples eigenes launchd.
1 Cron-Grundlagen
cron ist der klassische Unix-Dienst für zeitgesteuerte Aufgaben. Er stammt aus den 1970er Jahren und ist auf praktisch jedem Unix/Linux-System verfügbar.
1.1 Wie cron funktioniert
- Der
cron-Daemon läuft im Hintergrund - Er prüft jede Minute, ob geplante Aufgaben anstehen
- Aufgaben werden in Crontabs (cron tables) definiert
- Jeder Benutzer kann eine eigene Crontab haben
1.2 Crontab verwalten
| Befehl | Beschreibung |
|---|---|
crontab -e | Crontab bearbeiten |
crontab -l | Crontab anzeigen |
crontab -r | Crontab löschen |
crontab -u user -e | Crontab eines anderen Benutzers bearbeiten (root) |
Erste Verwendung:
crontab -e
Dies öffnet den Standard-Editor (meist vim oder nano). Um den Editor zu ändern:
export EDITOR=nano
crontab -e
1.3 Speicherorte
| Pfad | Beschreibung |
|---|---|
/var/at/tabs/ | Benutzer-Crontabs (macOS) |
/etc/crontab | System-Crontab |
/etc/cron.d/ | Zusätzliche System-Crontabs |
/etc/cron.daily/ | Täglich ausgeführte Skripte |
/etc/cron.weekly/ | Wöchentlich ausgeführte Skripte |
/etc/cron.monthly/ | Monatlich ausgeführte Skripte |
warning
Unter macOS existieren die /etc/cron.*-Verzeichnisse standardmäßig nicht, da Apple launchd bevorzugt.
2 Cron-Syntax & Beispiele
2.1 Grundsyntax
Eine Crontab-Zeile hat folgendes Format:
┌───────────── Minute (0-59)
│ ┌───────────── Stunde (0-23)
│ │ ┌───────────── Tag des Monats (1-31)
│ │ │ ┌───────────── Monat (1-12)
│ │ │ │ ┌───────────── Wochentag (0-7, 0 und 7 = Sonntag)
│ │ │ │ │
* * * * * Befehl
2.2 Sonderzeichen
| Zeichen | Bedeutung | Beispiel |
|---|---|---|
* | Jeder Wert | * * * * * = jede Minute |
, | Liste von Werten | 1,15,30 = Minute 1, 15 und 30 |
- | Bereich | 1-5 = Montag bis Freitag |
/ | Schrittweite | */15 = alle 15 Einheiten |
2.3 Beispiele
Zeitangaben:
| Ausdruck | Bedeutung |
|---|---|
* * * * * | Jede Minute |
0 * * * * | Jede Stunde (zur vollen Stunde) |
0 0 * * * | Täglich um Mitternacht |
0 6 * * * | Täglich um 6:00 Uhr |
30 8 * * 1-5 | Mo–Fr um 8:30 Uhr |
0 0 * * 0 | Jeden Sonntag um Mitternacht |
0 0 1 * * | Am 1. jeden Monats um Mitternacht |
0 0 1 1 * | Am 1. Januar um Mitternacht |
*/15 * * * * | Alle 15 Minuten |
0 */2 * * * | Alle 2 Stunden |
0 9-17 * * 1-5 | Mo–Fr, stündlich von 9–17 Uhr |
Vollständige Crontab-Beispiele:
# Backup jeden Tag um 2:00 Uhr
0 2 * * * /Users/max/scripts/backup.sh
# Log-Rotation jeden Sonntag um 3:00 Uhr
0 3 * * 0 /Users/max/scripts/rotate-logs.sh
# Alle 5 Minuten: System-Check
*/5 * * * * /Users/max/scripts/health-check.sh
# Werktags um 9:00: Bericht generieren
0 9 * * 1-5 /Users/max/scripts/daily-report.sh
# Am 1. und 15. jeden Monats
0 0 1,15 * * /Users/max/scripts/bi-monthly.sh
# Nur im Januar, täglich um 6:00
0 6 * 1 * /Users/max/scripts/january-task.sh
2.4 Spezielle Strings
Einige cron-Implementierungen unterstützen lesbare Kürzel:
| String | Äquivalent | Bedeutung |
|---|---|---|
@reboot | – | Bei Systemstart |
@yearly | 0 0 1 1 * | Jährlich |
@monthly | 0 0 1 * * | Monatlich |
@weekly | 0 0 * * 0 | Wöchentlich |
@daily | 0 0 * * * | Täglich |
@hourly | 0 * * * * | Stündlich |
@daily /Users/max/scripts/backup.sh
@reboot /Users/max/scripts/startup.sh
macOS-Kompatibilität:
macOS verwendet Vixie cron (BSD-basiert). Die Unterstützung der speziellen Strings:
| String | macOS | Anmerkung |
|---|---|---|
@yearly | ✅ | Funktioniert |
@monthly | ✅ | Funktioniert |
@weekly | ✅ | Funktioniert |
@daily | ✅ | Funktioniert |
@hourly | ✅ | Funktioniert |
@reboot | ❌ | Nicht zuverlässig |
Problem mit @reboot: Unter macOS startet der cron-Daemon erst nach dem Benutzer-Login, nicht beim Systemstart. Jobs mit @reboot werden daher nicht ausgeführt oder nur beim ersten Login nach einem Neustart.
Lösung für Startup-Tasks: Verwende stattdessen launchd mit RunAtLoad:
<key>RunAtLoad</key>
<true/>
Siehe [[#4 Erstellung von .plist-Jobs|Erstellung von .plist-Jobs]] für Details.
2.5 Umgebungsvariablen
Cron führt Befehle mit einer minimalen Umgebung aus. Wichtige Variablen sollten definiert werden:
# Umgebungsvariablen setzen
SHELL=/bin/zsh
PATH=/usr/local/bin:/usr/bin:/bin:/opt/homebrew/bin
HOME=/Users/max
MAILTO=max@example.com
# Jobs
0 * * * * /Users/max/scripts/task.sh
Wichtig: Der PATH in cron ist sehr eingeschränkt. Entweder:
- Vollständige Pfade zu Programmen verwenden
PATHin der Crontab setzenPATHim Skript selbst setzen
#!/bin/zsh
# Am Anfang des Skripts:
export PATH="/opt/homebrew/bin:/usr/local/bin:$PATH"
2.6 Ausgabe und Logging
Standardmäßig wird die Ausgabe per E-Mail gesendet (falls konfiguriert). Alternativen:
# Ausgabe in Datei
0 * * * * /script.sh >> /var/log/script.log 2>&1
# Ausgabe verwerfen
0 * * * * /script.sh > /dev/null 2>&1
# Nur Fehler loggen
0 * * * * /script.sh >> /var/log/script.log 2>&1
# Mit Zeitstempel
0 * * * * /script.sh 2>&1 | while read line; do echo "$(date): $line"; done >> /var/log/script.log
Logging-Wrapper-Skript:
#!/bin/zsh
# /Users/max/scripts/run-with-log.sh
LOGFILE="/var/log/cron-jobs.log"
SCRIPT="$1"
shift
echo "=== $(date '+%Y-%m-%d %H:%M:%S') - Start: $SCRIPT ===" >> "$LOGFILE"
"$SCRIPT" "$@" >> "$LOGFILE" 2>&1
EXIT_CODE=$?
echo "=== $(date '+%Y-%m-%d %H:%M:%S') - Ende: $SCRIPT (Exit: $EXIT_CODE) ===" >> "$LOGFILE"
echo "" >> "$LOGFILE"
Verwendung in Crontab:
0 * * * * /Users/max/scripts/run-with-log.sh /Users/max/scripts/task.sh
2.7 Häufige Probleme
1. Skript läuft nicht:
# Skript ausführbar machen
chmod +x /Users/max/scripts/script.sh
# Shebang prüfen
head -1 /Users/max/scripts/script.sh
# Sollte sein: #!/bin/zsh oder #!/bin/bash
2. Befehl nicht gefunden:
# FALSCH: brew ist nicht im PATH
0 * * * * brew update
# RICHTIG: Vollständiger Pfad
0 * * * * /opt/homebrew/bin/brew update
3. Berechtigungsprobleme:
# cron-Logs prüfen (macOS)
log show --predicate 'subsystem == "com.apple.cron"' --last 1h
3 launchd unter macOS
launchd ist Apples Init-System und Dienst-Manager. Es ist leistungsfähiger als cron und der empfohlene Weg für geplante Aufgaben unter macOS.
3.1 Konzepte
Agents vs. Daemons:
| Typ | Läuft als | Speicherort | Beschreibung |
|---|---|---|---|
| User Agent | Aktueller Benutzer | ~/Library/LaunchAgents/ | Benutzer-spezifische Aufgaben |
| Global Agent | Aktueller Benutzer | /Library/LaunchAgents/ | Für alle Benutzer, aber im Benutzerkontext |
| Global Daemon | root | /Library/LaunchDaemons/ | Systemweite Dienste |
| System Daemon | root | /System/Library/LaunchDaemons/ | macOS-Systemdienste (nicht bearbeiten!) |
Für die meisten Benutzeraufgaben: ~/Library/LaunchAgents/
3.2 launchctl – Das Verwaltungstool
| Befehl | Beschreibung |
|---|---|
launchctl list | Alle geladenen Jobs anzeigen |
| `launchctl list | grep LABEL` |
launchctl load FILE.plist | Job laden und aktivieren |
launchctl unload FILE.plist | Job deaktivieren und entladen |
launchctl start LABEL | Job sofort ausführen |
launchctl stop LABEL | Job stoppen |
launchctl kickstart gui/$(id -u)/LABEL | Job neu starten (moderne Syntax) |
Moderne Syntax (ab macOS 10.10):
# Benutzer-Agent laden
launchctl bootstrap gui/$(id -u) ~/Library/LaunchAgents/com.user.task.plist
# Benutzer-Agent entladen
launchctl bootout gui/$(id -u)/com.user.task
# System-Daemon laden (als root)
sudo launchctl bootstrap system /Library/LaunchDaemons/com.company.daemon.plist
3.3 Job-Status prüfen
# Alle Jobs auflisten
launchctl list
# Bestimmten Job finden
launchctl list | grep -i backup
# Job-Details anzeigen (moderne Syntax)
launchctl print gui/$(id -u)/com.user.backup
# Fehler prüfen
launchctl error <error_code>
4 Erstellung von .plist-Jobs
Property List (.plist) Dateien definieren launchd-Jobs im XML-Format.
4.1 Grundstruktur
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>com.benutzername.jobname</string>
<key>ProgramArguments</key>
<array>
<string>/pfad/zum/skript.sh</string>
</array>
<!-- Zeitplan oder Auslöser hier -->
</dict>
</plist>
4.2 Wichtige Schlüssel
Identifikation:
| Schlüssel | Typ | Beschreibung |
|---|---|---|
Label | String | Eindeutiger Bezeichner (erforderlich) |
Program | String | Auszuführendes Programm |
ProgramArguments | Array | Programm + Argumente |
Zeitsteuerung:
| Schlüssel | Typ | Beschreibung |
|---|---|---|
StartInterval | Integer | Intervall in Sekunden |
StartCalendarInterval | Dict/Array | Kalenderbasierte Ausführung |
Auslöser:
| Schlüssel | Typ | Beschreibung |
|---|---|---|
RunAtLoad | Boolean | Bei Laden ausführen |
WatchPaths | Array | Bei Dateiänderung ausführen |
QueueDirectories | Array | Ausführen wenn Dateien im Ordner |
StartOnMount | Boolean | Bei Volume-Mount ausführen |
Umgebung:
| Schlüssel | Typ | Beschreibung |
|---|---|---|
WorkingDirectory | String | Arbeitsverzeichnis |
EnvironmentVariables | Dict | Umgebungsvariablen |
UserName | String | Benutzer (nur Daemons) |
GroupName | String | Gruppe (nur Daemons) |
Ausgabe:
| Schlüssel | Typ | Beschreibung |
|---|---|---|
StandardOutPath | String | Stdout in Datei |
StandardErrorPath | String | Stderr in Datei |
Verhalten:
| Schlüssel | Typ | Beschreibung |
|---|---|---|
KeepAlive | Boolean/Dict | Prozess am Leben halten |
ThrottleInterval | Integer | Mindestzeit zwischen Neustarts |
Disabled | Boolean | Job deaktivieren |
4.3 StartCalendarInterval
Ähnlich wie cron-Syntax, aber als Dictionary:
| Schlüssel | Wertebereich |
|---|---|
Minute | 0–59 |
Hour | 0–23 |
Day | 1–31 |
Weekday | 0–7 (0 und 7 = Sonntag) |
Month | 1–12 |
Beispiele:
<!-- Täglich um 6:30 -->
<key>StartCalendarInterval</key>
<dict>
<key>Hour</key>
<integer>6</integer>
<key>Minute</key>
<integer>30</integer>
</dict>
<!-- Jeden Montag um 9:00 -->
<key>StartCalendarInterval</key>
<dict>
<key>Weekday</key>
<integer>1</integer>
<key>Hour</key>
<integer>9</integer>
<key>Minute</key>
<integer>0</integer>
</dict>
<!-- Mehrere Zeitpunkte (Array) -->
<key>StartCalendarInterval</key>
<array>
<dict>
<key>Hour</key>
<integer>9</integer>
<key>Minute</key>
<integer>0</integer>
</dict>
<dict>
<key>Hour</key>
<integer>17</integer>
<key>Minute</key>
<integer>0</integer>
</dict>
</array>
4.4 Vollständige Beispiele
Beispiel 1: Tägliches Backup um 2:00 Uhr
Datei: ~/Library/LaunchAgents/com.user.backup.plist
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>com.user.backup</string>
<key>ProgramArguments</key>
<array>
<string>/Users/max/scripts/backup.sh</string>
</array>
<key>StartCalendarInterval</key>
<dict>
<key>Hour</key>
<integer>2</integer>
<key>Minute</key>
<integer>0</integer>
</dict>
<key>StandardOutPath</key>
<string>/Users/max/logs/backup.log</string>
<key>StandardErrorPath</key>
<string>/Users/max/logs/backup-error.log</string>
<key>WorkingDirectory</key>
<string>/Users/max</string>
<key>EnvironmentVariables</key>
<dict>
<key>PATH</key>
<string>/opt/homebrew/bin:/usr/local/bin:/usr/bin:/bin</string>
</dict>
</dict>
</plist>
Beispiel 2: Alle 30 Minuten ausführen
Datei: ~/Library/LaunchAgents/com.user.sync.plist
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>com.user.sync</string>
<key>ProgramArguments</key>
<array>
<string>/Users/max/scripts/sync.sh</string>
</array>
<key>StartInterval</key>
<integer>1800</integer> <!-- 30 Minuten = 1800 Sekunden -->
<key>RunAtLoad</key>
<true/>
<key>StandardOutPath</key>
<string>/Users/max/logs/sync.log</string>
<key>StandardErrorPath</key>
<string>/Users/max/logs/sync.log</string>
</dict>
</plist>
Beispiel 3: Bei Dateiänderung ausführen (WatchPaths)
Datei: ~/Library/LaunchAgents/com.user.watcher.plist
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>com.user.watcher</string>
<key>ProgramArguments</key>
<array>
<string>/Users/max/scripts/process-downloads.sh</string>
</array>
<key>WatchPaths</key>
<array>
<string>/Users/max/Downloads</string>
</array>
<key>StandardOutPath</key>
<string>/Users/max/logs/watcher.log</string>
<key>StandardErrorPath</key>
<string>/Users/max/logs/watcher.log</string>
</dict>
</plist>
Beispiel 4: Bei Login ausführen
Datei: ~/Library/LaunchAgents/com.user.startup.plist
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>com.user.startup</string>
<key>ProgramArguments</key>
<array>
<string>/Users/max/scripts/startup.sh</string>
</array>
<key>RunAtLoad</key>
<true/>
</dict>
</plist>
Beispiel 5: Dienst dauerhaft laufen lassen (KeepAlive)
Datei: ~/Library/LaunchAgents/com.user.server.plist
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>com.user.server</string>
<key>ProgramArguments</key>
<array>
<string>/Users/max/scripts/server.sh</string>
</array>
<key>RunAtLoad</key>
<true/>
<key>KeepAlive</key>
<true/>
<key>ThrottleInterval</key>
<integer>10</integer>
<key>StandardOutPath</key>
<string>/Users/max/logs/server.log</string>
<key>StandardErrorPath</key>
<string>/Users/max/logs/server.log</string>
</dict>
</plist>
4.5 Job aktivieren
# 1. Datei erstellen/bearbeiten
nano ~/Library/LaunchAgents/com.user.backup.plist
# 2. Syntax prüfen
plutil -lint ~/Library/LaunchAgents/com.user.backup.plist
# 3. Job laden
launchctl load ~/Library/LaunchAgents/com.user.backup.plist
# 4. Prüfen ob geladen
launchctl list | grep com.user.backup
# 5. Manuell testen
launchctl start com.user.backup
4.6 Job deaktivieren
# Job entladen
launchctl unload ~/Library/LaunchAgents/com.user.backup.plist
# Job deaktivieren (bleibt entladen nach Neustart)
launchctl unload -w ~/Library/LaunchAgents/com.user.backup.plist
# Oder: Disabled-Key in plist setzen
4.7 Fehlersuche
# plist-Syntax prüfen
plutil -lint ~/Library/LaunchAgents/com.user.task.plist
# Geladene Jobs anzeigen
launchctl list | grep com.user
# Exit-Status prüfen (0 = OK, sonst Fehler)
launchctl list | grep com.user.task
# Ausgabe: PID Status Label
# - 0 com.user.task (Status 0 = OK)
# - 1 com.user.task (Status 1 = Fehler)
# System-Log prüfen
log show --predicate 'subsystem == "com.apple.xpc.launchd"' --last 1h | grep com.user
# Ausgabe-Logs prüfen
tail -f ~/logs/task.log
Häufige Fehler:
| Status | Bedeutung |
|---|---|
| 0 | Erfolgreich beendet |
| 1 | Allgemeiner Fehler |
| 78 | Konfigurationsfehler |
| 126 | Befehl nicht ausführbar |
| 127 | Befehl nicht gefunden |
5 Unterschiede Cron vs. launchd
5.1 Vergleichstabelle
| Merkmal | cron | launchd |
|---|---|---|
| Herkunft | Unix (1970er) | Apple (2005) |
| Konfiguration | Textdatei (crontab) | XML (.plist) |
| Syntax | Einfach, kompakt | Verbose, aber flexibel |
| Zeitsteuerung | Minutengenau | Sekunden möglich |
| Intervalle | Nur über Zeitpunkte | Native Intervall-Unterstützung |
| Auslöser | Nur Zeit | Zeit, Dateien, Netzwerk, etc. |
| Verpasste Jobs | Werden übersprungen | Werden nachgeholt |
| Umgebung | Minimal | Konfigurierbar |
| Logging | Manuell | Integriert |
| Dienst-Management | Nicht möglich | Vollständig (KeepAlive) |
| macOS-Integration | Basic | Vollständig |
| Portabilität | Hoch (alle Unix) | Nur macOS |
5.2 Wann cron verwenden?
✅ cron ist besser für:
- Einfache, zeitbasierte Aufgaben
- Portabilität (Skripte auch auf Linux nutzbar)
- Schnelle, unkomplizierte Einrichtung
- Erfahrene Unix-Nutzer
Beispiel-Anwendungsfälle:
# Einfaches tägliches Backup
0 2 * * * /Users/max/scripts/backup.sh
# Stündlicher Check
0 * * * * /Users/max/scripts/check.sh
5.3 Wann launchd verwenden?
✅ launchd ist besser für:
- macOS-spezifische Aufgaben
- Reaktion auf Ereignisse (Dateiänderungen, Netzwerk)
- Dienste die dauerhaft laufen sollen
- Bessere Fehlerbehandlung
- Integration mit macOS-Funktionen (Power Management, etc.)
- Wenn verpasste Jobs nachgeholt werden sollen
Beispiel-Anwendungsfälle:
- Ordner überwachen und bei Änderung reagieren
- Dienst der nach Absturz neu startet
- Task der nur bei Netzwerkverbindung läuft
5.4 Entscheidungshilfe
Aufgabe → Wahl
────────────────────────────────────────────────
Einfache Zeitsteuerung → cron
Reaktion auf Dateiänderungen → launchd
Dauerlaufenden Dienst → launchd
Portabilität zu Linux → cron
Nachholung verpasster Jobs → launchd
Schnelle Einrichtung → cron
macOS-Integration (Sleep/Wake) → launchd
Komplexe Bedingungen → launchd
5.5 Migration cron → launchd
cron:
30 2 * * * /Users/max/scripts/backup.sh
Äquivalentes launchd:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>com.user.backup</string>
<key>ProgramArguments</key>
<array>
<string>/Users/max/scripts/backup.sh</string>
</array>
<key>StartCalendarInterval</key>
<dict>
<key>Hour</key>
<integer>2</integer>
<key>Minute</key>
<integer>30</integer>
</dict>
</dict>
</plist>
5.6 Beide parallel nutzen
Es ist möglich, beide Systeme gleichzeitig zu verwenden:
- cron für einfache, portable Aufgaben
- launchd für macOS-spezifische Anforderungen
Tipp: Dokumentieren, welche Aufgaben wo konfiguriert sind:
# Alle aktiven Jobs anzeigen
echo "=== Cron Jobs ==="
crontab -l
echo ""
echo "=== LaunchAgents ==="
ls ~/Library/LaunchAgents/
echo ""
echo "=== Geladene Jobs ==="
launchctl list | grep com.user
5.7 Empfehlung
Für neue macOS-Projekte wird launchd empfohlen:
- Bessere Integration ins System
- Mehr Flexibilität bei Auslösern
- Zuverlässigere Ausführung
- Bessere Logging-Möglichkeiten
- Von Apple unterstützt und gepflegt
cron bleibt eine gute Wahl für:
- Einfache, zeitbasierte Tasks
- Cross-Platform-Kompatibilität
- Schnelle Einrichtung ohne XML
tmux & screen
Terminal-Multiplexer ermöglichen mehrere Terminal-Sitzungen in einem Fenster. Sie sind unverzichtbar für Remote-Arbeit, da Sessions auch nach Verbindungsabbruch weiterlaufen.
1 tmux Grundlagen
tmux (Terminal Multiplexer) ist der moderne Standard für Terminal-Multiplexing. Es ist leistungsfähiger und aktiver entwickelt als das ältere screen.
1.1 Installation
# macOS (Homebrew)
brew install tmux
# Version prüfen
tmux -V
1.2 Konzepte
tmux organisiert sich in drei Ebenen:
Server
└── Session (benannte Sitzung)
└── Window (Tab/Fenster)
└── Pane (geteilter Bereich)
| Begriff | Beschreibung |
|---|---|
| Server | Hintergrundprozess, verwaltet alle Sessions |
| Session | Benannte Arbeitsumgebung mit mehreren Windows |
| Window | Einzelnes Terminal (wie ein Tab) |
| Pane | Geteilter Bereich innerhalb eines Windows |
1.3 Erste Schritte
# Neue Session starten
tmux
# Neue benannte Session
tmux new -s arbeit
# Session verlassen (läuft weiter)
# Prefix + d (Ctrl+b, dann d)
# Sessions auflisten
tmux ls
# Zu Session verbinden
tmux attach -t arbeit
tmux a -t arbeit # Kurzform
# Letzte Session
tmux attach
tmux a
1.4 Prefix-Taste
Alle tmux-Befehle beginnen mit dem Prefix (Standard: Ctrl+b), gefolgt von einer Taste.
Ctrl+b, dann Befehlstaste
Beispiel: Um ein neues Fenster zu erstellen: Ctrl+b, loslassen, dann c.
Notation in dieser Referenz:
Prefix + xbedeutet: Ctrl+b drücken, loslassen, dann x drückenPrefixkann in der Konfiguration geändert werden (oft zuCtrl+a)
2 Fenster, Panes, Sessions
2.1 Session-Befehle
Tastenkürzel (innerhalb tmux):
| Kürzel | Beschreibung |
|---|---|
Prefix + d | Session detachen (verlassen) |
Prefix + s | Session-Liste anzeigen |
Prefix + $ | Session umbenennen |
Prefix + ( | Vorherige Session |
Prefix + ) | Nächste Session |
Kommandozeile:
# Neue Session
tmux new -s name
# Mit bestimmtem Startverzeichnis
tmux new -s projekt -c ~/projekte/webapp
# Session beenden
tmux kill-session -t name
# Alle Sessions beenden
tmux kill-server
# Session umbenennen
tmux rename-session -t alt neu
2.2 Window-Befehle (Fenster)
Windows sind wie Tabs innerhalb einer Session.
Tastenkürzel:
| Kürzel | Beschreibung |
|---|---|
Prefix + c | Neues Window erstellen |
Prefix + , | Window umbenennen |
Prefix + & | Window schließen (mit Bestätigung) |
Prefix + n | Nächstes Window |
Prefix + p | Vorheriges Window |
Prefix + 0-9 | Zu Window 0–9 wechseln |
Prefix + w | Window-Liste anzeigen |
Prefix + l | Letztes Window |
Prefix + ' | Window nach Nummer auswählen |
Prefix + f | Window nach Name suchen |
Kommandozeile:
# Neues Window in bestehender Session
tmux new-window -t session:
# Window mit Name
tmux new-window -t session: -n "logs"
# Window schließen
tmux kill-window -t session:2
2.3 Pane-Befehle (Bereiche)
Panes teilen ein Window in mehrere Bereiche.
Tastenkürzel:
| Kürzel | Beschreibung |
|---|---|
Prefix + % | Vertikal teilen (links/rechts) |
Prefix + " | Horizontal teilen (oben/unten) |
Prefix + x | Pane schließen (mit Bestätigung) |
Prefix + o | Zum nächsten Pane wechseln |
Prefix + ; | Zum letzten Pane wechseln |
Prefix + Pfeiltasten | Zu Pane in Richtung wechseln |
Prefix + q | Pane-Nummern anzeigen |
Prefix + q + 0-9 | Zu Pane mit Nummer wechseln |
Prefix + z | Pane zoomen (Vollbild toggle) |
Prefix + ! | Pane in eigenes Window verschieben |
Prefix + { | Pane nach links/oben tauschen |
Prefix + } | Pane nach rechts/unten tauschen |
Prefix + Space | Zwischen Layouts wechseln |
Pane-Größe ändern:
| Kürzel | Beschreibung |
|---|---|
Prefix + Ctrl+Pfeiltaste | Größe in kleinen Schritten |
Prefix + Alt+Pfeiltaste | Größe in großen Schritten |
Oder im Command-Mode (Prefix + :):
resize-pane -D 10 # 10 Zeilen nach unten
resize-pane -U 5 # 5 Zeilen nach oben
resize-pane -L 10 # 10 Spalten nach links
resize-pane -R 10 # 10 Spalten nach rechts
2.4 Layouts
tmux bietet vordefinierte Layouts:
| Layout | Beschreibung |
|---|---|
even-horizontal | Alle Panes nebeneinander, gleiche Breite |
even-vertical | Alle Panes untereinander, gleiche Höhe |
main-horizontal | Ein großes Pane oben, Rest unten |
main-vertical | Ein großes Pane links, Rest rechts |
tiled | Alle Panes gleichmäßig verteilt |
# Layout wählen
Prefix + Space # Durch Layouts rotieren
Prefix + Alt+1 # even-horizontal
Prefix + Alt+2 # even-vertical
Prefix + Alt+3 # main-horizontal
Prefix + Alt+4 # main-vertical
Prefix + Alt+5 # tiled
2.5 Copy-Mode
Der Copy-Mode ermöglicht Scrollen und Textauswahl.
| Kürzel | Beschreibung |
|---|---|
Prefix + [ | Copy-Mode starten |
q oder Escape | Copy-Mode beenden |
Pfeiltasten / hjkl | Navigation |
Ctrl+u / Ctrl+d | Halbe Seite hoch/runter |
g / G | Anfang / Ende |
/ | Vorwärts suchen |
? | Rückwärts suchen |
n / N | Nächster / Vorheriger Treffer |
Space | Auswahl starten |
Enter | Auswahl kopieren und beenden |
Prefix + ] | Einfügen |
Mit vi-Modus (empfohlen):
# In ~/.tmux.conf
setw -g mode-keys vi
# Dann im Copy-Mode:
# v = Auswahl starten
# y = Kopieren
# V = Zeilenweise auswählen
2.6 Command-Mode
Der Command-Mode erlaubt tmux-Befehle direkt einzugeben:
Prefix + :
Nützliche Befehle:
:new-session -s name # Neue Session
:kill-session # Aktuelle Session beenden
:source ~/.tmux.conf # Konfiguration neu laden
:list-keys # Alle Tastenkürzel anzeigen
:set -g option value # Option setzen
:setw -g option value # Window-Option setzen
3 Konfiguration
Die tmux-Konfiguration liegt in ~/.tmux.conf.
3.1 Grundlegende Einstellungen
# ~/.tmux.conf
# Prefix ändern (Ctrl+a statt Ctrl+b)
unbind C-b
set -g prefix C-a
bind C-a send-prefix
# Schnelleres Escape (wichtig für vim)
set -sg escape-time 0
# History vergrößern
set -g history-limit 50000
# Nummerierung bei 1 beginnen
set -g base-index 1
setw -g pane-base-index 1
# Automatisch umnummerieren
set -g renumber-windows on
# Terminal-Farben
set -g default-terminal "screen-256color"
set -ga terminal-overrides ",xterm-256color:Tc"
# Maus aktivieren
set -g mouse on
# Vi-Modus für Copy-Mode
setw -g mode-keys vi
# Focus-Events (für vim etc.)
set -g focus-events on
3.2 Tastenkürzel anpassen
# Intuitivere Split-Befehle
bind | split-window -h -c "#{pane_current_path}"
bind - split-window -v -c "#{pane_current_path}"
unbind '"'
unbind %
# Neues Window im aktuellen Pfad
bind c new-window -c "#{pane_current_path}"
# Pane-Navigation mit Alt+Pfeiltasten (ohne Prefix)
bind -n M-Left select-pane -L
bind -n M-Right select-pane -R
bind -n M-Up select-pane -U
bind -n M-Down select-pane -D
# Window-Navigation mit Shift+Pfeiltasten
bind -n S-Left previous-window
bind -n S-Right next-window
# Konfiguration neu laden
bind r source-file ~/.tmux.conf \; display "Config reloaded!"
# Panes synchronisieren (gleiche Eingabe in alle Panes)
bind S setw synchronize-panes
3.3 Statusleiste anpassen
# Statusleiste aktivieren
set -g status on
# Position
set -g status-position bottom
# Update-Intervall (Sekunden)
set -g status-interval 5
# Farben
set -g status-style 'bg=#333333 fg=#ffffff'
# Links: Session-Name
set -g status-left '#[fg=#000000,bg=#ffffff] #S #[default] '
set -g status-left-length 30
# Rechts: Datum und Uhrzeit
set -g status-right '#[fg=#ffffff] %Y-%m-%d %H:%M '
set -g status-right-length 50
# Window-Liste
set -g status-justify left
# Aktives Window hervorheben
setw -g window-status-current-style 'fg=#000000 bg=#00ff00 bold'
setw -g window-status-current-format ' #I:#W#F '
# Inaktive Windows
setw -g window-status-style 'fg=#888888'
setw -g window-status-format ' #I:#W#F '
3.4 Pane-Darstellung
# Aktiver Pane-Rahmen
set -g pane-active-border-style 'fg=#00ff00'
# Inaktiver Pane-Rahmen
set -g pane-border-style 'fg=#555555'
# Pane-Nummern-Anzeige
set -g display-panes-time 2000
set -g display-panes-colour '#555555'
set -g display-panes-active-colour '#00ff00'
3.5 Vollständige Beispielkonfiguration
# ~/.tmux.conf - Empfohlene Konfiguration
# === Grundeinstellungen ===
set -g prefix C-a # Prefix: Ctrl+a
unbind C-b
bind C-a send-prefix
set -sg escape-time 0 # Kein Delay nach Escape
set -g history-limit 50000 # Große History
set -g base-index 1 # Windows ab 1 nummerieren
setw -g pane-base-index 1 # Panes ab 1 nummerieren
set -g renumber-windows on # Automatisch umnummerieren
set -g mouse on # Maus aktivieren
setw -g mode-keys vi # Vi-Modus
set -g focus-events on # Focus-Events
# === Terminal ===
set -g default-terminal "screen-256color"
set -ga terminal-overrides ",*256col*:Tc"
# === Tastenkürzel ===
# Splits (im aktuellen Verzeichnis)
bind | split-window -h -c "#{pane_current_path}"
bind - split-window -v -c "#{pane_current_path}"
bind c new-window -c "#{pane_current_path}"
# Pane-Navigation (Alt+Pfeiltasten)
bind -n M-Left select-pane -L
bind -n M-Right select-pane -R
bind -n M-Up select-pane -U
bind -n M-Down select-pane -D
# Pane-Größe (Prefix + Shift+Pfeiltasten)
bind -r H resize-pane -L 5
bind -r J resize-pane -D 5
bind -r K resize-pane -U 5
bind -r L resize-pane -R 5
# Window-Navigation
bind -n S-Left previous-window
bind -n S-Right next-window
# Reload
bind r source-file ~/.tmux.conf \; display "Reloaded!"
# Copy-Mode (vi-style)
bind -T copy-mode-vi v send-keys -X begin-selection
bind -T copy-mode-vi y send-keys -X copy-selection-and-cancel
bind -T copy-mode-vi r send-keys -X rectangle-toggle
# macOS Clipboard
bind -T copy-mode-vi y send-keys -X copy-pipe-and-cancel "pbcopy"
# === Statusleiste ===
set -g status on
set -g status-position bottom
set -g status-interval 5
set -g status-style 'bg=#1a1a1a fg=#808080'
set -g status-left '#[fg=#1a1a1a,bg=#87d700,bold] #S #[default] '
set -g status-left-length 30
set -g status-right '#[fg=#808080] %d.%m.%Y #[fg=#c0c0c0]%H:%M '
set -g status-right-length 50
setw -g window-status-format ' #I:#W '
setw -g window-status-current-format '#[fg=#1a1a1a,bg=#87d700,bold] #I:#W '
# === Panes ===
set -g pane-border-style 'fg=#404040'
set -g pane-active-border-style 'fg=#87d700'
# === Messages ===
set -g message-style 'bg=#87d700 fg=#1a1a1a bold'
set -g display-time 2000
3.6 Konfiguration neu laden
# Innerhalb tmux
Prefix + :
source ~/.tmux.conf
# Oder mit Tastenkürzel (wenn konfiguriert)
Prefix + r
# Von außerhalb
tmux source-file ~/.tmux.conf
4 screen-Vergleich
screen ist der ältere Terminal-Multiplexer (seit 1987). Es ist auf vielen Systemen vorinstalliert.
4.1 screen Grundlagen
# Neue Session
screen
# Benannte Session
screen -S arbeit
# Session verlassen (detach)
Ctrl+a, dann d
# Sessions auflisten
screen -ls
# Wieder verbinden
screen -r arbeit
# Verbinden (auch wenn attached)
screen -x arbeit
4.2 screen-Befehle
| Kürzel | Beschreibung |
|---|---|
Ctrl+a d | Detach |
Ctrl+a c | Neues Window |
Ctrl+a n | Nächstes Window |
Ctrl+a p | Vorheriges Window |
Ctrl+a " | Window-Liste |
Ctrl+a 0-9 | Zu Window wechseln |
Ctrl+a A | Window umbenennen |
Ctrl+a k | Window beenden |
Ctrl+a S | Horizontal teilen |
| `Ctrl+a | ` |
Ctrl+a Tab | Zwischen Regionen wechseln |
Ctrl+a X | Aktuelle Region schließen |
Ctrl+a [ | Copy-Mode |
Ctrl+a ] | Einfügen |
Ctrl+a ? | Hilfe |
4.3 screen-Konfiguration
Die Konfiguration liegt in ~/.screenrc:
# ~/.screenrc
# Startmeldung deaktivieren
startup_message off
# Scrollback-Buffer
defscrollback 10000
# Visual Bell statt Audio
vbell on
# Statusleiste
hardstatus alwayslastline
hardstatus string '%{= kG}[ %{G}%H %{g}][%= %{= kw}%?%-Lw%?%{r}(%{W}%n*%f%t%?(%u)%?%{r})%{w}%?%+Lw%?%?%= %{g}][%{B} %m-%d %{W}%c %{g}]'
# Shell
shell -$SHELL
4.4 Vergleich tmux vs. screen
| Merkmal | tmux | screen |
|---|---|---|
| Erste Version | 2007 | 1987 |
| Aktive Entwicklung | Ja | Minimal |
| Vorinstalliert | Selten | Oft |
| Prefix | Ctrl+b | Ctrl+a |
| Vertikale Splits | Native | Mit Patch |
| Scripting | Sehr gut | Begrenzt |
| Konfiguration | Flexibel | Einfach |
| Statusleiste | Sehr anpassbar | Begrenzt |
| Pane-Handling | Ausgezeichnet | Rudimentär |
| Copy-Mode | Vi/Emacs | Emacs-style |
| Session-Sharing | Einfach | Möglich |
4.5 Wann welches Tool?
tmux verwenden wenn:
- Modernes System mit Homebrew/apt
- Komplexe Layouts mit vielen Panes
- Umfangreiche Anpassungen gewünscht
- Scripting/Automatisierung benötigt
screen verwenden wenn:
- Auf älteren/minimalen Systemen arbeiten
- Kein tmux installiert und keine Root-Rechte
- Einfache Anforderungen (nur Sessions)
- Gewohnte Umgebung
Empfehlung: Auf eigenen Systemen tmux installieren und verwenden. screen-Kenntnisse sind nützlich für Server ohne tmux.
5 Remote-Session-Management
Der Hauptvorteil von Terminal-Multiplexern: Sessions überleben Verbindungsabbrüche.
5.1 Typischer SSH-Workflow
# 1. Mit Server verbinden
ssh user@server
# 2. tmux starten oder verbinden
tmux new -s arbeit
# oder
tmux attach -t arbeit
# 3. Arbeiten...
# 4. Sauber trennen (Session läuft weiter)
Prefix + d
# 5. SSH beenden
exit
# 6. Später wieder verbinden
ssh user@server
tmux attach -t arbeit
# Alles ist noch da!
5.2 Automatische tmux-Session
In ~/.bashrc oder ~/.zshrc auf dem Server:
# Automatisch tmux starten bei SSH-Login
if [-z "$TMUX"](-z%20"$TMUX".md) && [-n "$SSH_CONNECTION"](-n%20"$SSH_CONNECTION".md); then
tmux attach -t default || tmux new -s default
fi
Vorsicht: Kann Probleme bei SCP/SFTP verursachen. Besser:
# Nur bei interaktiver Shell
if [-z "$TMUX"](-z%20"$TMUX".md) && [-n "$SSH_CONNECTION"](-n%20"$SSH_CONNECTION".md) && [$- == *i*]($-%20==%20*i*.md); then
tmux attach -t default 2>/dev/null || tmux new -s default
fi
5.3 SSH-Verbindung in tmux
# Lokale tmux-Session
tmux new -s remote-arbeit
# Innerhalb tmux: SSH-Verbindung
ssh user@server
# Wenn Verbindung abbricht: tmux-Session lokal intakt
# Einfach erneut SSH starten
5.4 Mehrere Server verwalten
# Session für jeden Server
tmux new -s server1 -d "ssh user@server1"
tmux new -s server2 -d "ssh user@server2"
# Zwischen Sessions wechseln
Prefix + s
# Oder: Ein Window pro Server
tmux new -s servers
tmux new-window -t servers -n "web" "ssh user@webserver"
tmux new-window -t servers -n "db" "ssh user@dbserver"
tmux new-window -t servers -n "app" "ssh user@appserver"
5.5 Session-Sharing
Mehrere Benutzer können dieselbe Session sehen (Pair Programming, Support):
tmux:
# Benutzer 1: Session erstellen
tmux new -s shared
# Benutzer 2: Gleiche Session (beide sehen dasselbe)
tmux attach -t shared
# Benutzer 2: Eigene Ansicht (unabhängige Window-Auswahl)
tmux new -t shared -s user2
screen:
# Multi-User aktivieren (in .screenrc oder zur Laufzeit)
multiuser on
acladd username
# Anderer Benutzer verbindet
screen -x user/sessionname
5.6 Persistente Layouts
Session beim Start mit vordefiniertem Layout:
Script-basiert:
#!/bin/zsh
# ~/scripts/dev-session.sh
SESSION="dev"
# Prüfen ob Session existiert
tmux has-session -t $SESSION 2>/dev/null
if [ $? != 0 ]; then
# Neue Session mit erstem Window
tmux new-session -d -s $SESSION -n "editor"
# Editor-Window: vim
tmux send-keys -t $SESSION:editor "cd ~/projekt && vim" Enter
# Zweites Window: Server
tmux new-window -t $SESSION -n "server"
tmux send-keys -t $SESSION:server "cd ~/projekt && npm run dev" Enter
# Drittes Window: Terminal (gesplittet)
tmux new-window -t $SESSION -n "term"
tmux split-window -h -t $SESSION:term
tmux send-keys -t $SESSION:term.1 "cd ~/projekt" Enter
tmux send-keys -t $SESSION:term.2 "cd ~/projekt && git status" Enter
# Zum Editor-Window wechseln
tmux select-window -t $SESSION:editor
fi
# Zur Session verbinden
tmux attach -t $SESSION
Mit tmuxinator (empfohlen für komplexe Setups):
# Installation
brew install tmuxinator
# Neues Projekt erstellen
tmuxinator new projekt
# ~/.config/tmuxinator/projekt.yml
name: projekt
root: ~/projekt
windows:
- editor:
layout: main-vertical
panes:
- vim
- git status
- server:
panes:
- npm run dev
- logs:
panes:
- tail -f logs/app.log
- tail -f logs/error.log
# Session starten
tmuxinator start projekt
# Session beenden
tmuxinator stop projekt
5.7 tmux und SSH-Agent
SSH-Agent-Forwarding kann in tmux problematisch sein. Lösung:
# In ~/.tmux.conf
set -g update-environment "SSH_AUTH_SOCK SSH_AGENT_PID"
# Oder: Symlink-Methode in ~/.zshrc
if [-n "$SSH_AUTH_SOCK"](-n%20"$SSH_AUTH_SOCK".md) && ["$SSH_AUTH_SOCK" != "$HOME/.ssh/ssh_auth_sock"]("$SSH_AUTH_SOCK"%20!=%20"$HOME/.ssh/ssh_auth_sock".md); then
ln -sf "$SSH_AUTH_SOCK" "$HOME/.ssh/ssh_auth_sock"
fi
export SSH_AUTH_SOCK="$HOME/.ssh/ssh_auth_sock"
5.8 Nützliche Aliase
# In ~/.zshrc
# tmux-Aliase
alias ta='tmux attach -t'
alias tl='tmux list-sessions'
alias tn='tmux new -s'
alias tk='tmux kill-session -t'
# Schnell zu Session oder neue erstellen
t() {
if [-n "$1"](-n%20"$1".md); then
tmux attach -t "$1" 2>/dev/null || tmux new -s "$1"
else
tmux attach 2>/dev/null || tmux new -s main
fi
}
5.9 Cheatsheet
Session-Management:
tmux Neue Session
tmux new -s NAME Benannte Session
tmux ls Sessions auflisten
tmux attach -t NAME Zu Session verbinden
tmux kill-session -t NAME Session beenden
Prefix + d Detach
Prefix + s Session-Auswahl
Windows:
Prefix + c Neues Window
Prefix + n / p Nächstes / Vorheriges
Prefix + 0-9 Zu Window wechseln
Prefix + , Umbenennen
Prefix + & Schließen
Prefix + w Window-Liste
Panes:
Prefix + % Vertikal teilen
Prefix + " Horizontal teilen
Prefix + Pfeiltasten Navigation
Prefix + z Zoom (Vollbild)
Prefix + x Schließen
Prefix + Space Layout wechseln
Prefix + ! Pane → Window
Copy-Mode:
Prefix + [ Copy-Mode starten
q / Escape Beenden
Space / v Auswahl starten
Enter / y Kopieren
Prefix + ] Einfügen
SSH-Keys
SSH-Keys ermöglichen sichere, passwortlose Authentifizierung bei Remote-Servern. Sie sind sicherer als Passwörter und essentiell für automatisierte Workflows.
1 SSH-Keys erstellen & verwalten
1.1 Funktionsweise
SSH verwendet asymmetrische Kryptografie:
| Schlüssel | Datei | Verbleib | Funktion |
|---|---|---|---|
| Private Key | ~/.ssh/id_ed25519 | Lokal (geheim!) | Zum Signieren |
| Public Key | ~/.ssh/id_ed25519.pub | Server | Zum Verifizieren |
Der Private Key verlässt niemals den lokalen Rechner. Der Public Key wird auf alle Server kopiert, zu denen man sich verbinden möchte.
1.2 Algorithmen
| Algorithmus | Empfehlung | Anmerkung |
|---|---|---|
| Ed25519 | ✅ Empfohlen | Modern, schnell, sicher, kurze Keys |
| RSA | ⚠️ Akzeptabel | Mindestens 4096 Bit, für ältere Systeme |
| ECDSA | ❌ Vermeiden | Potenzielle Schwächen |
| DSA | ❌ Veraltet | Nicht mehr verwenden |
1.3 Key erstellen
Ed25519 (empfohlen):
ssh-keygen -t ed25519 -C "kommentar@example.com"
RSA (für Kompatibilität):
ssh-keygen -t rsa -b 4096 -C "kommentar@example.com"
Interaktiver Dialog:
Generating public/private ed25519 key pair.
Enter file in which to save the key (/Users/max/.ssh/id_ed25519):
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /Users/max/.ssh/id_ed25519
Your public key has been saved in /Users/max/.ssh/id_ed25519.pub
Optionen:
| Option | Beschreibung |
|---|---|
-t TYPE | Algorithmus (ed25519, rsa, ecdsa) |
-b BITS | Schlüssellänge (nur RSA: 4096) |
-C "text" | Kommentar (meist E-Mail) |
-f DATEI | Ausgabedatei |
-N "phrase" | Passphrase (leer = keine) |
Beispiele:
# Standard Ed25519 Key
ssh-keygen -t ed25519 -C "max@example.com"
# Key mit bestimmtem Namen
ssh-keygen -t ed25519 -C "github" -f ~/.ssh/github_ed25519
# Key ohne Passphrase (für Automatisierung)
ssh-keygen -t ed25519 -C "automation" -f ~/.ssh/automation -N ""
# RSA Key für ältere Systeme
ssh-keygen -t rsa -b 4096 -C "legacy-server" -f ~/.ssh/legacy_rsa
1.4 Passphrase
Die Passphrase verschlüsselt den Private Key:
| Mit Passphrase | Ohne Passphrase |
|---|---|
| Key ist verschlüsselt | Key ist unverschlüsselt |
| Bei Diebstahl geschützt | Sofort nutzbar bei Diebstahl |
| Muss bei Verwendung eingegeben werden | Keine Eingabe nötig |
| SSH-Agent speichert temporär | Für Automatisierung geeignet |
Empfehlung: Immer Passphrase verwenden, SSH-Agent für Komfort nutzen.
Passphrase ändern:
ssh-keygen -p -f ~/.ssh/id_ed25519
1.5 Dateien und Berechtigungen
Standard-Speicherort: ~/.ssh/
| Datei | Beschreibung | Berechtigung |
|---|---|---|
id_ed25519 | Private Key | 600 (nur Besitzer) |
id_ed25519.pub | Public Key | 644 (lesbar) |
authorized_keys | Erlaubte Keys | 600 |
known_hosts | Bekannte Server | 644 |
config | SSH-Konfiguration | 600 |
Berechtigungen setzen:
# Verzeichnis
chmod 700 ~/.ssh
# Private Keys
chmod 600 ~/.ssh/id_*
chmod 600 ~/.ssh/*_ed25519
chmod 600 ~/.ssh/*_rsa
# Public Keys
chmod 644 ~/.ssh/*.pub
# Konfigurationsdateien
chmod 600 ~/.ssh/config
chmod 600 ~/.ssh/authorized_keys
chmod 644 ~/.ssh/known_hosts
SSH verweigert Keys mit zu offenen Berechtigungen!
1.6 Public Key auf Server kopieren
Methode 1: ssh-copy-id (empfohlen)
ssh-copy-id user@server
# Bestimmten Key
ssh-copy-id -i ~/.ssh/github_ed25519.pub user@server
Methode 2: Manuell
# Public Key anzeigen
cat ~/.ssh/id_ed25519.pub
# Auf Server: Key in authorized_keys einfügen
ssh user@server
mkdir -p ~/.ssh
chmod 700 ~/.ssh
echo "PUBLICKEY" >> ~/.ssh/authorized_keys
chmod 600 ~/.ssh/authorized_keys
Methode 3: Einzeiler
cat ~/.ssh/id_ed25519.pub | ssh user@server "mkdir -p ~/.ssh && chmod 700 ~/.ssh && cat >> ~/.ssh/authorized_keys && chmod 600 ~/.ssh/authorized_keys"
1.7 Keys verwalten
Alle Keys auflisten:
ls -la ~/.ssh/
# Fingerprints anzeigen
for key in ~/.ssh/id_*; do
[-f "$key" && "$key" != *.pub](-f%20"$key"%20&&%20"$key"%20!=%20*.pub.md) && ssh-keygen -lf "$key"
done
Key-Fingerprint anzeigen:
# MD5 (älteres Format)
ssh-keygen -l -E md5 -f ~/.ssh/id_ed25519.pub
# SHA256 (Standard)
ssh-keygen -l -f ~/.ssh/id_ed25519.pub
Public Key aus Private Key extrahieren:
ssh-keygen -y -f ~/.ssh/id_ed25519 > ~/.ssh/id_ed25519.pub
Key löschen:
# Beide Dateien entfernen
rm ~/.ssh/id_ed25519 ~/.ssh/id_ed25519.pub
# Aus authorized_keys auf Server entfernen
ssh user@server
nano ~/.ssh/authorized_keys # Zeile entfernen
1.8 Mehrere Keys
Für verschiedene Zwecke separate Keys erstellen:
# Persönlicher Key
ssh-keygen -t ed25519 -C "personal" -f ~/.ssh/personal_ed25519
# Arbeit
ssh-keygen -t ed25519 -C "work" -f ~/.ssh/work_ed25519
# GitHub
ssh-keygen -t ed25519 -C "github" -f ~/.ssh/github_ed25519
# Automation (ohne Passphrase)
ssh-keygen -t ed25519 -C "automation" -f ~/.ssh/automation_ed25519 -N ""
Die Zuordnung erfolgt über ~/.ssh/config (siehe Abschnitt 5.2).
2 SSH-Konfiguration (~/.ssh/config)
Die SSH-Konfiguration vereinfacht Verbindungen und ermöglicht hostspezifische Einstellungen.
2.1 Grundstruktur
Host ALIAS
Option Wert
Option Wert
Einfaches Beispiel:
Host server
HostName 192.168.1.100
User admin
Port 22
Statt ssh admin@192.168.1.100 genügt nun ssh server.
2.2 Wichtige Optionen
| Option | Beschreibung | Beispiel |
|---|---|---|
Host | Alias oder Pattern | server, *.example.com |
HostName | Echter Hostname/IP | 192.168.1.100 |
User | Benutzername | admin |
Port | SSH-Port | 22, 2222 |
IdentityFile | Private Key | ~/.ssh/work_ed25519 |
IdentitiesOnly | Nur angegebene Keys | yes |
ForwardAgent | Agent-Forwarding | yes |
ProxyJump | Jump-Host | bastion |
LocalForward | Port-Forwarding lokal | 8080 localhost:80 |
RemoteForward | Port-Forwarding remote | 9090 localhost:8080 |
ServerAliveInterval | Keep-alive Intervall | 60 |
ServerAliveCountMax | Keep-alive Versuche | 3 |
Compression | Komprimierung | yes |
AddKeysToAgent | Key zum Agent | yes |
UseKeychain | macOS Keychain | yes |
2.3 Vollständige Beispielkonfiguration
# ~/.ssh/config
# === Globale Einstellungen ===
Host *
AddKeysToAgent yes
UseKeychain yes
IdentitiesOnly yes
ServerAliveInterval 60
ServerAliveCountMax 3
# === Arbeit ===
Host work
HostName work-server.company.com
User max.mustermann
IdentityFile ~/.ssh/work_ed25519
Host work-*
User max.mustermann
IdentityFile ~/.ssh/work_ed25519
Host work-web
HostName 10.0.1.10
Host work-db
HostName 10.0.1.20
Host work-app
HostName 10.0.1.30
# === Persönlich ===
Host home
HostName home.dyndns.org
User max
Port 2222
IdentityFile ~/.ssh/personal_ed25519
Host pi
HostName 192.168.1.50
User pi
IdentityFile ~/.ssh/personal_ed25519
# === GitHub ===
Host github.com
HostName github.com
User git
IdentityFile ~/.ssh/github_ed25519
# Zweiter GitHub Account
Host github-work
HostName github.com
User git
IdentityFile ~/.ssh/work_github_ed25519
# === GitLab ===
Host gitlab.com
HostName gitlab.com
User git
IdentityFile ~/.ssh/gitlab_ed25519
# === Jump Host / Bastion ===
Host bastion
HostName bastion.company.com
User jump
IdentityFile ~/.ssh/work_ed25519
Host internal-*
ProxyJump bastion
User admin
IdentityFile ~/.ssh/work_ed25519
Host internal-web
HostName 10.10.1.10
Host internal-db
HostName 10.10.1.20
# === Port Forwarding ===
Host tunnel-db
HostName dbserver.company.com
User admin
LocalForward 5432 localhost:5432
IdentityFile ~/.ssh/work_ed25519
# === Alte/Legacy Server ===
Host legacy
HostName old-server.example.com
User root
IdentityFile ~/.ssh/legacy_rsa
PubkeyAcceptedAlgorithms +ssh-rsa
HostkeyAlgorithms +ssh-rsa
2.4 Wildcards und Patterns
| Pattern | Beschreibung |
|---|---|
* | Beliebige Zeichen |
? | Ein beliebiges Zeichen |
! | Negation |
# Alle Hosts
Host *
ServerAliveInterval 60
# Alle .company.com Hosts
Host *.company.com
User admin
IdentityFile ~/.ssh/work_ed25519
# Alle außer bestimmte
Host * !github.com !gitlab.com
IdentityFile ~/.ssh/default_ed25519
2.5 Jump Hosts (ProxyJump)
Verbindung über einen Zwischenserver (Bastion Host):
# Klassisch (alt)
Host internal
ProxyCommand ssh -W %h:%p bastion
# Modern (empfohlen)
Host internal
ProxyJump bastion
Mehrere Hops:
Host deep-internal
ProxyJump bastion,middle-server
Kommandozeile:
ssh -J bastion internal-server
ssh -J bastion,middle deep-server
2.6 Port Forwarding
Local Forward (Zugriff auf Remote-Dienst):
# Remote-Datenbank lokal verfügbar machen
Host tunnel-postgres
HostName dbserver.com
LocalForward 5432 localhost:5432
ssh tunnel-postgres
# Dann: psql -h localhost -p 5432
Remote Forward (Lokalen Dienst remote verfügbar):
# Lokalen Webserver remote verfügbar machen
Host expose-local
HostName server.com
RemoteForward 8080 localhost:3000
Dynamic Forward (SOCKS Proxy):
Host socks-proxy
HostName server.com
DynamicForward 1080
ssh socks-proxy
# Browser: SOCKS5 Proxy auf localhost:1080
2.7 Mehrere GitHub/GitLab Accounts
# Persönlicher GitHub Account
Host github.com
HostName github.com
User git
IdentityFile ~/.ssh/github_personal
# Arbeits-GitHub Account
Host github-work
HostName github.com
User git
IdentityFile ~/.ssh/github_work
Verwendung:
# Persönlich (Standard)
git clone git@github.com:user/repo.git
# Arbeit
git clone git@github-work:company/repo.git
# In bestehendem Repo Remote ändern
git remote set-url origin git@github-work:company/repo.git
2.8 Reihenfolge und Priorität
SSH liest die Config von oben nach unten. Der erste Match für jede Option gewinnt.
# RICHTIG: Spezifisch vor allgemein
Host work-server
User admin
Host *
User default
# FALSCH: Allgemein überschreibt spezifisch
Host *
User default
Host work-server
User admin # Wird ignoriert!
Empfohlene Struktur:
- Spezifische Hosts
- Gruppen-Patterns (
work-*,*.company.com) - Globale Einstellungen (
Host *)
3 SSH-Agent, Konfiguration und Sicherheit
3.1 SSH-Agent Grundlagen
Der SSH-Agent speichert entschlüsselte Private Keys im Speicher, sodass die Passphrase nicht bei jeder Verbindung eingegeben werden muss.
Funktionsweise:
┌─────────────────────────────────────────────────────┐
│ SSH-Agent │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ Key 1 │ │ Key 2 │ │ Key 3 │ │
│ │ (entschl.) │ │ (entschl.) │ │ (entschl.) │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ │
└─────────────────────────────────────────────────────┘
↑ ↑ ↑
ssh server1 ssh server2 git push
(kein Passwort) (kein Passwort) (kein Passwort)
3.2 Agent unter macOS
macOS startet den SSH-Agent automatisch. Die Integration mit der Keychain speichert Passphrasen dauerhaft.
Keychain-Integration aktivieren:
# ~/.ssh/config
Host *
AddKeysToAgent yes
UseKeychain yes
Key manuell zur Keychain hinzufügen:
# Key zum Agent hinzufügen (Passphrase in Keychain speichern)
ssh-add --apple-use-keychain ~/.ssh/id_ed25519
# Alle Standard-Keys laden
ssh-add --apple-load-keychain
warning
Ältere macOS-Versionen verwenden -K statt --apple-use-keychain und -A statt --apple-load-keychain.
3.3 Agent-Befehle
| Befehl | Beschreibung |
|---|---|
ssh-add | Standard-Keys hinzufügen |
ssh-add DATEI | Bestimmten Key hinzufügen |
ssh-add -l | Geladene Keys auflisten |
ssh-add -L | Public Keys der geladenen Keys |
ssh-add -d DATEI | Key entfernen |
ssh-add -D | Alle Keys entfernen |
ssh-add -t SEKUNDEN | Key mit Zeitlimit |
Beispiele:
# Key hinzufügen
ssh-add ~/.ssh/work_ed25519
# Alle Keys anzeigen
ssh-add -l
# Key für 1 Stunde hinzufügen
ssh-add -t 3600 ~/.ssh/sensitive_ed25519
# Alle Keys entfernen (Sicherheit)
ssh-add -D
3.4 Agent Forwarding
Agent Forwarding erlaubt die Nutzung lokaler Keys auf Remote-Servern, ohne die Keys dorthin zu kopieren.
Lokal → Server A → Server B
(Agent mit Keys) (kein Key) (kein Key)
nutzt lokalen nutzt lokalen
Agent Agent via A
Aktivieren:
# ~/.ssh/config
Host trusted-server
ForwardAgent yes
Oder per Kommandozeile:
ssh -A trusted-server
caution
Agent Forwarding nur für vertrauenswürdige Server aktivieren! Ein kompromittierter Server könnte den Agent missbrauchen.
Sicherer: ProxyJump statt Agent Forwarding
Host internal
ProxyJump bastion
ProxyJump ist sicherer, da der Zwischenserver keinen Zugriff auf den Agent erhält.
3.5 Sicherheits-Best-Practices
Key-Management:
| Praxis | Beschreibung |
|---|---|
| Passphrase verwenden | Schützt bei Diebstahl des Keys |
| Separate Keys | Pro Zweck/Dienst eigene Keys |
| Ed25519 verwenden | Modernster, sicherster Algorithmus |
| Keys rotieren | Regelmäßig neue Keys erstellen |
| Alte Keys entfernen | Nicht mehr benötigte Keys löschen |
Berechtigungen:
# Einmalig: Alle Berechtigungen korrekt setzen
chmod 700 ~/.ssh
chmod 600 ~/.ssh/id_* ~/.ssh/config ~/.ssh/authorized_keys
chmod 644 ~/.ssh/*.pub ~/.ssh/known_hosts
authorized_keys absichern:
# Optionen vor dem Key einschränken
# In ~/.ssh/authorized_keys auf dem Server:
# Nur von bestimmter IP
from="192.168.1.100" ssh-ed25519 AAAA... user@host
# Kein Agent-Forwarding, kein PTY
no-agent-forwarding,no-pty ssh-ed25519 AAAA... automation@host
# Nur bestimmten Befehl erlauben
command="/usr/local/bin/backup.sh" ssh-ed25519 AAAA... backup@host
# Kombination
from="10.0.0.*",no-agent-forwarding,no-port-forwarding ssh-ed25519 AAAA...
Verfügbare Optionen:
| Option | Beschreibung |
|---|---|
from="PATTERN" | Nur von bestimmten IPs/Hosts |
command="CMD" | Nur diesen Befehl ausführen |
no-agent-forwarding | Agent-Forwarding verbieten |
no-port-forwarding | Port-Forwarding verbieten |
no-pty | Kein Terminal (nur Befehle) |
no-X11-forwarding | X11-Forwarding verbieten |
environment="VAR=val" | Umgebungsvariable setzen |
3.6 known_hosts
Die Datei ~/.ssh/known_hosts speichert Fingerprints bekannter Server und schützt vor Man-in-the-Middle-Angriffen.
Erste Verbindung:
The authenticity of host 'server.com (192.168.1.100)' can't be established.
ED25519 key fingerprint is SHA256:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.
Are you sure you want to continue connecting (yes/no/[fingerprint])?
Fingerprint verifizieren:
# Auf dem Server
ssh-keygen -lf /etc/ssh/ssh_host_ed25519_key.pub
# Vergleichen mit angezeigtem Fingerprint
Host entfernen (bei legitimem Key-Wechsel):
ssh-keygen -R server.com
ssh-keygen -R 192.168.1.100
Hashed known_hosts (mehr Privatsphäre):
# ~/.ssh/config
Host *
HashKnownHosts yes
3.7 Server-Konfiguration (sshd_config)
Auf dem Server in /etc/ssh/sshd_config:
# Nur Key-Authentifizierung
PubkeyAuthentication yes
PasswordAuthentication no
PermitEmptyPasswords no
# Root-Login verbieten oder einschränken
PermitRootLogin no
# Oder: PermitRootLogin prohibit-password
# Nur bestimmte User erlauben
AllowUsers admin deploy
# Nur bestimmte Gruppen
AllowGroups sshusers
# Agent-Forwarding global deaktivieren
AllowAgentForwarding no
# Idle-Timeout
ClientAliveInterval 300
ClientAliveCountMax 2
# Sichere Algorithmen (modern)
KexAlgorithms curve25519-sha256,curve25519-sha256@libssh.org
HostKeyAlgorithms ssh-ed25519,rsa-sha2-512,rsa-sha2-256
Ciphers chacha20-poly1305@openssh.com,aes256-gcm@openssh.com
MACs hmac-sha2-512-etm@openssh.com,hmac-sha2-256-etm@openssh.com
Nach Änderungen:
# Syntax prüfen
sudo sshd -t
# Dienst neu starten
sudo systemctl restart sshd
# Oder macOS:
sudo launchctl stop com.openssh.sshd
sudo launchctl start com.openssh.sshd
3.8 Troubleshooting
Verbindung debuggen:
# Verbose-Modus
ssh -v user@server # Level 1
ssh -vv user@server # Level 2
ssh -vvv user@server # Level 3 (sehr detailliert)
Häufige Probleme:
| Problem | Ursache | Lösung |
|---|---|---|
Permission denied (publickey) | Key nicht akzeptiert | Key in authorized_keys prüfen |
Bad permissions | Falsche Dateirechte | chmod 600 ~/.ssh/id_* |
Host key verification failed | Server-Key geändert | ssh-keygen -R host |
Connection refused | SSH nicht aktiv / Port | Firewall, sshd-Status prüfen |
Too many authentication failures | Zu viele Keys probiert | IdentitiesOnly yes |
Agent prüfen:
# Agent läuft?
echo $SSH_AUTH_SOCK
# Keys geladen?
ssh-add -l
# Agent neu starten (falls nötig)
eval $(ssh-agent -s)
ssh-add
Berechtigungen prüfen:
# Lokal
ls -la ~/.ssh/
# Auf Server
ls -la ~/.ssh/
ls -la ~/.ssh/authorized_keys
3.9 Nützliche Aliase und Funktionen
# ~/.zshrc
# SSH-Key Fingerprints anzeigen
alias ssh-fingerprints='for key in ~/.ssh/id_*; do [-f "$key" && "$key" != *.pub](-f%20"$key"%20&&%20"$key"%20!=%20*.pub.md) && ssh-keygen -lf "$key"; done'
# Neuen Ed25519 Key erstellen
ssh-newkey() {
local name="${1:-id_ed25519}"
local comment="${2:-$(whoami)@$(hostname)}"
ssh-keygen -t ed25519 -C "$comment" -f ~/.ssh/"$name"
}
# Key zu Server kopieren
ssh-copykey() {
local key="${1:-~/.ssh/id_ed25519.pub}"
local server="$2"
if [-z "$server"](-z%20"$server".md); then
echo "Usage: ssh-copykey [keyfile] server"
return 1
fi
ssh-copy-id -i "$key" "$server"
}
# SSH-Verbindung testen
ssh-test() {
ssh -o BatchMode=yes -o ConnectTimeout=5 "$1" echo "OK" 2>&1
}
3.10 Cheatsheet
Keys erstellen:
ssh-keygen -t ed25519 -C "comment" Neuer Ed25519 Key
ssh-keygen -t ed25519 -f ~/.ssh/name Mit bestimmtem Namen
ssh-keygen -p -f ~/.ssh/id_ed25519 Passphrase ändern
ssh-keygen -y -f private > public Public aus Private
ssh-keygen -lf ~/.ssh/id_ed25519 Fingerprint anzeigen
Keys verteilen:
ssh-copy-id user@server Key auf Server kopieren
ssh-copy-id -i ~/.ssh/key.pub user@server Bestimmten Key kopieren
Agent:
ssh-add Standard-Keys laden
ssh-add ~/.ssh/key Bestimmten Key laden
ssh-add -l Geladene Keys anzeigen
ssh-add -d ~/.ssh/key Key entfernen
ssh-add -D Alle Keys entfernen
ssh-add --apple-use-keychain ~/.ssh/key In macOS Keychain (neu)
Verbindung:
ssh server Mit Alias verbinden
ssh -i ~/.ssh/key user@server Mit bestimmtem Key
ssh -J bastion internal Über Jump-Host
ssh -L 8080:localhost:80 server Local Port Forward
ssh -v server Debug-Modus
Wartung:
ssh-keygen -R hostname Host aus known_hosts entfernen
chmod 700 ~/.ssh Verzeichnis-Berechtigung
chmod 600 ~/.ssh/id_* ~/.ssh/config Datei-Berechtigungen
ZLE / ZLE-Widgets
Der Zsh Line Editor (ZLE) ist das Herzstück der Kommandozeilen-Bearbeitung in zsh. Er ermöglicht umfangreiche Anpassungen der Eingabe, eigene Tastenkürzel und mächtige Widgets.
1 Grundlagen & Architektur
1.1 Was ist ZLE?
ZLE ist der eingebaute Zeileneditor von zsh, vergleichbar mit readline in bash. Er verarbeitet alle Tastatureingaben und stellt Funktionen bereit für:
- Cursor-Bewegung und Textbearbeitung
- History-Navigation
- Tab-Completion
- Vi- und Emacs-Modus
- Benutzerdefinierte Widgets
1.2 Keymaps
ZLE organisiert Tastenbelegungen in Keymaps:
| Keymap | Beschreibung |
|---|---|
emacs | Emacs-Modus (Standard) |
viins | Vi-Insert-Modus |
vicmd | Vi-Command-Modus |
visual | Vi-Visual-Modus |
isearch | Inkrementelle Suche |
command | Befehlseingabe (nach M-x) |
main | Alias für aktive Keymap |
Aktuelle Keymap anzeigen:
bindkey -l # Alle Keymaps auflisten
bindkey -M emacs # Bindungen der emacs-Keymap
bindkey -M viins # Bindungen des vi-Insert-Modus
Keymap wechseln:
# Emacs-Modus (Standard)
bindkey -e
# Vi-Modus
bindkey -v
1.3 Widgets
Ein Widget ist eine Funktion, die an eine Taste gebunden werden kann. ZLE stellt über 150 eingebaute Widgets bereit.
Eingebaute Widgets anzeigen:
zle -la # Alle Widgets auflisten
zle -la | wc -l # Anzahl
zle -la | grep hist # Widgets mit "hist" im Namen
Wichtige eingebaute Widgets:
| Widget | Beschreibung |
|---|---|
accept-line | Zeile ausführen (Enter) |
backward-char | Cursor links |
forward-char | Cursor rechts |
backward-word | Wort zurück |
forward-word | Wort vor |
beginning-of-line | Zeilenanfang |
end-of-line | Zeilenende |
backward-delete-char | Backspace |
delete-char | Delete |
kill-line | Bis Zeilenende löschen |
backward-kill-line | Bis Zeilenanfang löschen |
kill-word | Wort löschen |
yank | Einfügen (aus Kill-Ring) |
undo | Rückgängig |
redo | Wiederholen |
clear-screen | Bildschirm löschen |
history-search-backward | History rückwärts suchen |
history-search-forward | History vorwärts suchen |
expand-or-complete | Tab-Completion |
self-insert | Zeichen einfügen |
1.4 Aktuelle Bindungen anzeigen
# Alle Bindungen
bindkey
# Bestimmte Taste
bindkey "^A" # Was macht Ctrl+A?
bindkey "^[[A" # Was macht Pfeil-Hoch?
# Widget suchen
bindkey | grep kill
1.5 Escape-Sequenzen
Tasten werden als Escape-Sequenzen dargestellt:
| Notation | Bedeutung | Beispiel |
|---|---|---|
^X | Ctrl+X | ^A = Ctrl+A |
^[ | Escape / Alt | ^[b = Alt+B |
\e | Escape (alternativ) | \eb = Alt+B |
| `^[CSI (Terminal-Sequenz) | ^[[A = Pfeil hoch | |
^[O | SS3 (Terminal-Sequenz) | ^[OA = Pfeil hoch (alt) |
Terminal-Sequenzen ermitteln:
# Methode 1: cat
cat -v
# Dann Taste drücken, z.B. Pfeil hoch zeigt: ^[[A
# Methode 2: read
read -k
# Taste drücken
# Methode 3: Ctrl+V in zsh
# Ctrl+V drücken, dann Taste → zeigt Sequenz
Häufige Terminal-Sequenzen:
| Taste | Sequenz |
|---|---|
| Pfeil hoch | ^[[A |
| Pfeil runter | ^[[B |
| Pfeil rechts | ^[[C |
| Pfeil links | ^[[D |
| Home | ^[[H oder ^[OH |
| End | ^[[F oder ^[OF |
| Delete | ^[[3~ |
| Page Up | ^[[5~ |
| Page Down | ^[[6~ |
| F1–F12 | ^[OP bis ^[[24~ |
1.6 ZLE-Variablen
Innerhalb eines Widgets verfügbare Variablen:
| Variable | Beschreibung |
|---|---|
$BUFFER | Gesamte Eingabezeile |
$LBUFFER | Text links vom Cursor |
$RBUFFER | Text rechts vom Cursor |
$CURSOR | Cursor-Position (0-basiert) |
$WIDGET | Name des aktuellen Widgets |
$LASTWIDGET | Name des vorherigen Widgets |
$KEYS | Gedrückte Tasten |
$KEYMAP | Aktive Keymap |
$PREBUFFER | Vorherige Zeilen (Multiline) |
$REGION_ACTIVE | Ist Region aktiv? |
$MARK | Position der Markierung |
2 Eigene Widgets schreiben
2.1 Widget-Grundstruktur
# Widget-Funktion definieren
my-widget() {
# Code hier
}
# Als Widget registrieren
zle -N my-widget
# An Taste binden
bindkey "^X^M" my-widget
2.2 Einfache Beispiele
Text einfügen:
# Aktuelles Datum einfügen
insert-date() {
LBUFFER+=$(date +%Y-%m-%d)
}
zle -N insert-date
bindkey "^Xd" insert-date
# Timestamp einfügen
insert-timestamp() {
LBUFFER+=$(date +"%Y-%m-%d %H:%M:%S")
}
zle -N insert-timestamp
bindkey "^Xt" insert-timestamp
Buffer manipulieren:
# Zeile in Großbuchstaben
uppercase-line() {
BUFFER=${BUFFER:u}
}
zle -N uppercase-line
bindkey "^Xu" uppercase-line
# Zeile in Kleinbuchstaben
lowercase-line() {
BUFFER=${BUFFER:l}
}
zle -N lowercase-line
bindkey "^Xl" lowercase-line
# Wort unter Cursor in Großbuchstaben
uppercase-word() {
local word="${LBUFFER##* }"
LBUFFER="${LBUFFER% *} ${word:u}"
}
zle -N uppercase-word
Sudo voranstellen:
prepend-sudo() {
if [[ $BUFFER != sudo\ *](`.md); then
BUFFER="sudo $BUFFER"
CURSOR+=5
fi
}
zle -N prepend-sudo
bindkey "^[s" prepend-sudo # Alt+S
2.3 Mit History arbeiten
# Letzten Befehl mit sudo wiederholen
sudo-last-command() {
BUFFER="sudo $(fc -ln -1)"
zle accept-line
}
zle -N sudo-last-command
bindkey "^[!" sudo-last-command
# Letztes Argument des vorherigen Befehls
insert-last-arg() {
zle insert-last-word
}
zle -N insert-last-arg
bindkey "^[." insert-last-arg # Alt+. (oft schon belegt)
2.4 Externe Befehle einbinden
# fzf für History-Suche
fzf-history() {
local selected
selected=$(fc -ln 1 | fzf --tac --no-sort)
if [-n "$selected"](-n%20"$selected".md); then
BUFFER="$selected"
CURSOR=$#BUFFER
fi
zle redisplay
}
zle -N fzf-history
bindkey "^R" fzf-history
# fzf für Dateiauswahl
fzf-file() {
local file
file=$(fzf)
if [-n "$file"](-n%20"$file".md); then
LBUFFER+="${(q)file}" # Quoted einfügen
fi
zle redisplay
}
zle -N fzf-file
bindkey "^Xf" fzf-file
# fzf für Verzeichniswechsel
fzf-cd() {
local dir
dir=$(find . -type d 2>/dev/null | fzf)
if [-n "$dir"](-n%20"$dir".md); then
cd "$dir"
zle reset-prompt
fi
}
zle -N fzf-cd
bindkey "^Xc" fzf-cd
2.5 Clipboard-Integration
# Auswahl in Clipboard kopieren (macOS)
copy-to-clipboard() {
echo -n "$BUFFER" | pbcopy
zle -M "Copied to clipboard"
}
zle -N copy-to-clipboard
bindkey "^Xy" copy-to-clipboard
# Aus Clipboard einfügen
paste-from-clipboard() {
LBUFFER+=$(pbpaste)
}
zle -N paste-from-clipboard
bindkey "^Xp" paste-from-clipboard
# Kill-Ring nach Clipboard
copy-kill-ring() {
echo -n "$CUTBUFFER" | pbcopy
zle -M "Kill buffer copied"
}
zle -N copy-kill-ring
2.6 Widgets mit Parametern
# Widget das andere Widgets aufruft
surround-with-quotes() {
BUFFER="\"$BUFFER\""
CURSOR=$#BUFFER
}
zle -N surround-with-quotes
bindkey "^X\"" surround-with-quotes
# Flexibler: Wrapper-Funktion
surround-with() {
local open="$1" close="$2"
BUFFER="${open}${BUFFER}${close}"
CURSOR=$#BUFFER
}
surround-parens() { surround-with '(' ')'; }
surround-brackets() { surround-with '[' ']'; }
surround-braces() { surround-with '{' '}'; }
surround-single() { surround-with "'" "'"; }
surround-double() { surround-with '"' '"'; }
zle -N surround-parens
zle -N surround-brackets
zle -N surround-braces
zle -N surround-single
zle -N surround-double
bindkey "^X(" surround-parens
bindkey "^X[" surround-brackets
bindkey "^X{" surround-braces
bindkey "^X'" surround-single
bindkey '^X"' surround-double
2.7 Rückgabewerte und Fehlerbehandlung
# Widget mit Fehlermeldung
safe-rm() {
if [-z "$BUFFER"](-z%20"$BUFFER".md); then
zle -M "Buffer ist leer"
return 1
fi
if ["$BUFFER" == rm\ *]("$BUFFER"%20==%20rm\%20*.md); then
BUFFER="${BUFFER/rm /rm -i }"
zle -M "rm → rm -i (interaktiv)"
fi
}
zle -N safe-rm
bindkey "^Xr" safe-rm
3 Erweiterte Shortcuts / ZLE-Bindings
3.1 bindkey Syntax
bindkey [optionen] "taste" widget
| Option | Beschreibung |
|---|---|
-e | Emacs-Keymap aktivieren |
-v | Vi-Keymap aktivieren |
-M keymap | Binding in bestimmter Keymap |
-r "taste" | Binding entfernen |
-s "taste" "string" | Makro (String einfügen) |
-l | Keymaps auflisten |
-L | Bindungen als bindkey-Befehle |
3.2 Tastenkombinationen definieren
# Einzelne Taste
bindkey "^A" beginning-of-line
# Tastensequenz
bindkey "^X^F" fzf-file
# Mit Escape/Alt
bindkey "^[b" backward-word # Alt+B
bindkey "\eb" backward-word # Alternative Notation
# Pfeiltasten
bindkey "^[[A" history-search-backward
bindkey "^[[B" history-search-forward
# Funktionstasten
bindkey "^[OP" my-f1-widget # F1
bindkey "^[[15~" my-f5-widget # F5
3.3 Makros (String-Bindungen)
Mit -s wird ein String eingefügt statt ein Widget aufgerufen:
# Pipe zu less
bindkey -s "^Xl" " | less"
# Pipe zu grep
bindkey -s "^Xg" " | grep "
# Redirect Stderr
bindkey -s "^Xe" " 2>&1"
# Redirect zu /dev/null
bindkey -s "^Xn" " > /dev/null 2>&1"
# Git Status
bindkey -s "^Gs" "git status\n"
# Git Diff
bindkey -s "^Gd" "git diff\n"
# Häufige Befehle
bindkey -s "^Ll" "ll\n"
bindkey -s "^Lc" "clear\n"
tip
\n führt den Befehl direkt aus.
3.4 Keymap-spezifische Bindungen
# Nur im Vi-Insert-Modus
bindkey -M viins "jk" vi-cmd-mode
# Nur im Vi-Command-Modus
bindkey -M vicmd "H" beginning-of-line
bindkey -M vicmd "L" end-of-line
# Nur im Emacs-Modus
bindkey -M emacs "^Xe" edit-command-line
3.5 Bindung entfernen
# Binding entfernen
bindkey -r "^X^K"
# In bestimmter Keymap
bindkey -M viins -r "^A"
3.6 Alle Bindungen exportieren/importieren
# Aktuelle Bindungen als Befehle ausgeben
bindkey -L > ~/bindkeys-backup.zsh
# Wiederherstellen
source ~/bindkeys-backup.zsh
4 Erweiterte Tastenkombinationen
4.1 Emacs-Modus Referenz
Navigation:
| Kürzel | Widget | Beschreibung |
|---|---|---|
Ctrl+A | beginning-of-line | Zeilenanfang |
Ctrl+E | end-of-line | Zeilenende |
Ctrl+F | forward-char | Zeichen vor |
Ctrl+B | backward-char | Zeichen zurück |
Alt+F | forward-word | Wort vor |
Alt+B | backward-word | Wort zurück |
Bearbeitung:
| Kürzel | Widget | Beschreibung |
|---|---|---|
Ctrl+D | delete-char | Zeichen löschen |
Ctrl+H | backward-delete-char | Backspace |
Ctrl+W | backward-kill-word | Wort rückwärts löschen |
Alt+D | kill-word | Wort vorwärts löschen |
Ctrl+K | kill-line | Bis Zeilenende löschen |
Ctrl+U | backward-kill-line | Bis Zeilenanfang löschen |
Ctrl+Y | yank | Einfügen |
Alt+Y | yank-pop | Vorheriges aus Kill-Ring |
Ctrl+T | transpose-chars | Zeichen tauschen |
Alt+T | transpose-words | Wörter tauschen |
Alt+U | up-case-word | Wort GROSS |
Alt+L | down-case-word | Wort klein |
Alt+C | capitalize-word | Wort Kapitalisieren |
History:
| Kürzel | Widget | Beschreibung |
|---|---|---|
Ctrl+P | up-line-or-history | Vorheriger Befehl |
Ctrl+N | down-line-or-history | Nächster Befehl |
Ctrl+R | history-incremental-search-backward | History suchen rückwärts |
Ctrl+S | history-incremental-search-forward | History suchen vorwärts |
Alt+< | beginning-of-buffer-or-history | Erste History |
Alt+> | end-of-buffer-or-history | Letzte History |
Alt+. | insert-last-word | Letztes Argument |
Sonstiges:
| Kürzel | Widget | Beschreibung |
|---|---|---|
Ctrl+L | clear-screen | Bildschirm löschen |
Ctrl+_ | undo | Rückgängig |
Ctrl+X Ctrl+U | undo | Rückgängig (alternativ) |
Ctrl+X Ctrl+E | edit-command-line | In Editor öffnen |
Tab | expand-or-complete | Completion |
Ctrl+G | send-break | Abbrechen |
4.2 Vi-Modus Referenz
Modus wechseln:
| Kürzel | Beschreibung |
|---|---|
Escape | Insert → Command |
i | Insert vor Cursor |
a | Insert nach Cursor |
A | Insert am Zeilenende |
I | Insert am Zeilenanfang |
o | Neue Zeile darunter |
O | Neue Zeile darüber |
Navigation (Command-Modus):
| Kürzel | Beschreibung |
|---|---|
h / l | Links / Rechts |
j / k | History runter / hoch |
w / b | Wort vor / zurück |
e | Wortende |
0 / $ | Zeilenanfang / -ende |
^ | Erstes Nicht-Whitespace |
f{char} | Vorwärts zu Zeichen |
F{char} | Rückwärts zu Zeichen |
t{char} | Vor Zeichen |
T{char} | Nach Zeichen (rückwärts) |
Bearbeitung (Command-Modus):
| Kürzel | Beschreibung |
|---|---|
x | Zeichen löschen |
X | Zeichen davor löschen |
dd | Ganze Zeile löschen |
D | Bis Zeilenende löschen |
dw | Wort löschen |
cw | Wort ändern |
cc | Zeile ändern |
C | Bis Zeilenende ändern |
r{char} | Zeichen ersetzen |
R | Replace-Modus |
yy | Zeile kopieren |
yw | Wort kopieren |
p / P | Einfügen nach/vor |
u | Undo |
Ctrl+R | Redo |
History (Command-Modus):
| Kürzel | Beschreibung |
|---|---|
/pattern | Vorwärts suchen |
?pattern | Rückwärts suchen |
n / N | Nächster / Vorheriger Treffer |
4.3 Eigene Keymap erstellen
# Neue Keymap basierend auf emacs
bindkey -N mymap emacs
# Anpassungen
bindkey -M mymap "^Xd" insert-date
bindkey -M mymap "^Xs" prepend-sudo
# Keymap aktivieren
bindkey -A mymap main
4.4 Contextuelle Bindings
# Binding nur bei bestimmter Eingabe
# Beispiel: Tab verhält sich unterschiedlich
smart-tab() {
if [-z "$LBUFFER"](-z%20"$LBUFFER".md); then
# Leere Zeile: 4 Spaces einfügen
LBUFFER+=" "
elif ["$LBUFFER" =~ '^ +$']("$LBUFFER"%20=~%20'^%20+$'.md); then
# Nur Whitespace: weitere Spaces
LBUFFER+=" "
else
# Sonst: normale Completion
zle expand-or-complete
fi
}
zle -N smart-tab
bindkey "^I" smart-tab
5 Beispiele & Use-Cases
5.1 Produktivitäts-Widgets
Befehl in Editor öffnen:
# Bereits eingebaut, aber oft nicht gebunden
autoload -U edit-command-line
zle -N edit-command-line
bindkey "^Xe" edit-command-line
bindkey "^X^E" edit-command-line
Git-Integration:
# Git Branch wechseln mit fzf
fzf-git-branch() {
local branch
branch=$(git branch --all | grep -v HEAD | fzf --preview 'git log --oneline -20 {1}')
branch=${branch#remotes/origin/}
branch=${branch## }
if [-n "$branch"](-n%20"$branch".md); then
BUFFER="git checkout $branch"
zle accept-line
fi
}
zle -N fzf-git-branch
bindkey "^Gb" fzf-git-branch
# Git Status anzeigen (ohne Ausführung)
show-git-status() {
zle -M "$(git status -s 2>/dev/null || echo 'Not a git repo')"
}
zle -N show-git-status
bindkey "^Gs" show-git-status
# Git Add mit fzf
fzf-git-add() {
local files
files=$(git status -s | fzf -m | awk '{print $2}')
if [-n "$files"](-n%20"$files".md); then
BUFFER="git add ${files//$'\n'/ }"
CURSOR=$#BUFFER
fi
zle redisplay
}
zle -N fzf-git-add
bindkey "^Ga" fzf-git-add
Verzeichnis-Navigation:
# Schnell zu häufigen Verzeichnissen
goto-projects() {
local dir
dir=$(find ~/projects -maxdepth 1 -type d | fzf)
if [-n "$dir"](-n%20"$dir".md); then
cd "$dir"
zle reset-prompt
fi
}
zle -N goto-projects
bindkey "^Xp" goto-projects
# Parent Directory
goto-parent() {
cd ..
zle reset-prompt
}
zle -N goto-parent
bindkey "^X." goto-parent
# Zurück zum vorherigen Verzeichnis
goto-previous() {
cd - > /dev/null
zle reset-prompt
}
zle -N goto-previous
bindkey "^X-" goto-previous
5.2 Textmanipulation
Pipe-Operatoren schnell einfügen:
# Pipe-Menü
pipe-menu() {
local pipes=(
"| less"
"| grep "
"| head -20"
"| tail -20"
"| wc -l"
"| sort"
"| sort -u"
"| xargs "
"| awk '{print \$1}'"
"| sed 's///g'"
"> /dev/null 2>&1"
"2>&1"
)
local selected
selected=$(printf '%s\n' "${pipes[@]}" | fzf --prompt="Pipe: ")
if [-n "$selected"](-n%20"$selected".md); then
LBUFFER+=" $selected"
fi
zle redisplay
}
zle -N pipe-menu
bindkey "^X|" pipe-menu
Pfad expandieren:
# ~ und Variablen expandieren
expand-path() {
BUFFER="${(e)BUFFER}"
}
zle -N expand-path
bindkey "^Xx" expand-path
# Aktuelles Wort zu absolutem Pfad
expand-to-absolute() {
local word="${LBUFFER##* }"
local rest="${LBUFFER% *}"
local abs="${word:A}"
if ["$rest" == "$LBUFFER"]("$rest"%20==%20"$LBUFFER".md); then
LBUFFER="$abs"
else
LBUFFER="$rest $abs"
fi
}
zle -N expand-to-absolute
bindkey "^Xa" expand-to-absolute
Wort-Operationen:
# Wort duplizieren
duplicate-word() {
local word="${LBUFFER##* }"
LBUFFER+=" $word"
}
zle -N duplicate-word
bindkey "^Xw" duplicate-word
# Wörter rückwärts
reverse-words() {
local words=(${=BUFFER})
BUFFER="${(j: :)${(Oa)words}}"
}
zle -N reverse-words
5.3 History-Erweiterungen
History mit Preview:
fzf-history-widget() {
local selected
selected=$(fc -rl 1 | fzf +s --tac \
--preview 'echo {}' \
--preview-window down:3:wrap)
if [-n "$selected"](-n%20"$selected".md); then
# Nummer entfernen
BUFFER="${selected#* }"
CURSOR=$#BUFFER
fi
zle redisplay
}
zle -N fzf-history-widget
bindkey "^R" fzf-history-widget
Letzten Befehl modifizieren:
# Letzten Befehl holen und editierbar machen
recall-last-command() {
BUFFER=$(fc -ln -1)
CURSOR=$#BUFFER
}
zle -N recall-last-command
bindkey "^[r" recall-last-command
5.4 Prompt-Integration
# Prompt neu zeichnen nach Widget
update-prompt() {
# Prompt-relevante Variablen aktualisieren
zle reset-prompt
}
# Nach cd immer Prompt aktualisieren
cd-and-update() {
if [-n "$BUFFER"](-n%20"$BUFFER".md); then
zle accept-line
zle reset-prompt
fi
}
5.5 Debugging-Widgets
# Aktuellen Buffer anzeigen
debug-buffer() {
zle -M "BUFFER: '$BUFFER' | LBUFFER: '$LBUFFER' | CURSOR: $CURSOR"
}
zle -N debug-buffer
bindkey "^Xb" debug-buffer
# Letzte Tasten anzeigen
debug-keys() {
zle -M "KEYS: '$KEYS' | WIDGET: '$WIDGET' | LASTWIDGET: '$LASTWIDGET'"
}
zle -N debug-keys
bindkey "^Xk" debug-keys
# Widget-Liste durchsuchen
search-widgets() {
local widget
widget=$(zle -la | fzf --prompt="Widget: ")
if [-n "$widget"](-n%20"$widget".md); then
zle -M "Widget: $widget"
fi
}
zle -N search-widgets
bindkey "^X?" search-widgets
5.6 Vollständige .zshrc-Integration
# ~/.zshrc - ZLE-Konfiguration
# === Grundeinstellungen ===
bindkey -e # Emacs-Modus
# === Standard-Verbesserungen ===
bindkey "^[[A" history-search-backward # Pfeil hoch: History mit Prefix
bindkey "^[[B" history-search-forward # Pfeil runter: History mit Prefix
bindkey "^[[H" beginning-of-line # Home
bindkey "^[[F" end-of-line # End
bindkey "^[[3~" delete-char # Delete
# === Editor ===
autoload -U edit-command-line
zle -N edit-command-line
bindkey "^Xe" edit-command-line
bindkey "^X^E" edit-command-line
# === Eigene Widgets ===
# Sudo voranstellen
prepend-sudo() {
[$BUFFER != sudo\ *]($BUFFER%20!=%20sudo\%20*.md) && BUFFER="sudo $BUFFER" && ((CURSOR+=5))
}
zle -N prepend-sudo
bindkey "^[s" prepend-sudo
# Datum einfügen
insert-date() { LBUFFER+=$(date +%Y-%m-%d); }
zle -N insert-date
bindkey "^Xd" insert-date
# Clipboard (macOS)
copy-buffer() { echo -n "$BUFFER" | pbcopy; zle -M "Copied"; }
paste-buffer() { LBUFFER+=$(pbpaste); }
zle -N copy-buffer
zle -N paste-buffer
bindkey "^Xy" copy-buffer
bindkey "^Xp" paste-buffer
# === Makros ===
bindkey -s "^Xl" " | less"
bindkey -s "^Xg" " | grep "
bindkey -s "^Xn" " > /dev/null 2>&1"
# === fzf-Integration (falls installiert) ===
if command -v fzf &> /dev/null; then
# History
fzf-history() {
local cmd=$(fc -ln 1 | fzf --tac --no-sort)
[-n "$cmd"](-n%20"$cmd".md) && BUFFER="$cmd" && CURSOR=$#BUFFER
zle redisplay
}
zle -N fzf-history
bindkey "^R" fzf-history
# Dateien
fzf-file() {
local file=$(fzf)
[-n "$file"](-n%20"$file".md) && LBUFFER+="${(q)file}"
zle redisplay
}
zle -N fzf-file
bindkey "^Xf" fzf-file
# Verzeichnisse
fzf-cd() {
local dir=$(find . -type d 2>/dev/null | fzf)
[-n "$dir"](-n%20"$dir".md) && cd "$dir" && zle reset-prompt
}
zle -N fzf-cd
bindkey "^Xc" fzf-cd
fi
5.7 Cheatsheet
Widget erstellen:
widget-name() { ... } # Funktion definieren
zle -N widget-name # Als Widget registrieren
bindkey "^Xk" widget-name # An Taste binden
Wichtige Variablen:
$BUFFER # Gesamte Zeile
$LBUFFER # Links vom Cursor
$RBUFFER # Rechts vom Cursor
$CURSOR # Cursor-Position
Bindkey:
bindkey # Alle Bindungen
bindkey "^X" # Was macht Ctrl+X?
bindkey "^Xk" widget # Widget binden
bindkey -s "^Xk" "string" # Makro binden
bindkey -r "^Xk" # Binding entfernen
bindkey -M viins "jk" vi-cmd # Keymap-spezifisch
Escape-Sequenzen:
^X = Ctrl+X
^[ = Escape / Alt
^[[A = Pfeil hoch
^[[B = Pfeil runter
\n = Enter (für Makros)
Dateisystem & Volumes
Dieses Kapitel behandelt fortgeschrittene Dateisystem-Operationen unter macOS: symbolische und harte Links, Datei-Metadaten, Volume-Management, Disk Images und Backup-Werkzeuge.
1 Links
Links ermöglichen es, auf Dateien oder Verzeichnisse an mehreren Stellen im Dateisystem zu verweisen, ohne die Daten zu duplizieren.
1.1 Symbolische Links (ln -s)
Ein symbolischer Link (Symlink, Softlink) ist ein Verweis auf einen Pfad. Er funktioniert wie eine Verknüpfung und kann auf Dateien oder Verzeichnisse zeigen – auch über Dateisystemgrenzen hinweg.
Syntax:
ln -s ZIEL LINKNAME
Beispiele:
# Symlink auf eine Datei
ln -s ~/Documents/config.yaml ~/.config/app/config.yaml
# Symlink auf ein Verzeichnis
ln -s ~/Dropbox/Projekte ~/Projekte
# Symlink mit relativem Pfad
cd ~/bin
ln -s ../scripts/backup.sh backup
# Symlink in anderem Verzeichnis erstellen
ln -s /opt/homebrew/bin/python3 /usr/local/bin/python
Eigenschaften:
| Merkmal | Symbolischer Link |
|---|---|
| Verweist auf | Pfad (String) |
| Ziel gelöscht | Link wird “broken” (toter Link) |
| Über Dateisysteme | ✅ Ja |
| Auf Verzeichnisse | ✅ Ja |
| Eigene Inode | ✅ Ja (eigene Datei) |
| Erkennung | ls -l zeigt l und -> |
Symlink erkennen:
ls -l ~/Projekte
# lrwxr-xr-x 1 max staff 20 Jan 15 10:30 Projekte -> Dropbox/Projekte
# Nur Symlinks anzeigen
ls -la | grep "^l"
# Mit file-Befehl
file ~/Projekte
# /Users/max/Projekte: symbolic link to Dropbox/Projekte
1.2 Harte Links (ln)
Ein harter Link ist ein zusätzlicher Verzeichniseintrag für dieselbe Datei (Inode). Die Datei existiert erst dann nicht mehr, wenn alle harten Links gelöscht wurden.
Syntax:
ln ZIEL LINKNAME
Beispiele:
# Harter Link auf Datei
ln original.txt hardlink.txt
# Beide zeigen auf dieselbe Inode
ls -li original.txt hardlink.txt
# 12345678 -rw-r--r-- 2 max staff 100 Jan 15 10:30 hardlink.txt
# 12345678 -rw-r--r-- 2 max staff 100 Jan 15 10:30 original.txt
# ^-- gleiche Inode-Nummer ^-- Link-Count = 2
Eigenschaften:
| Merkmal | Harter Link |
|---|---|
| Verweist auf | Inode (Daten direkt) |
| Ziel gelöscht | Link funktioniert weiter |
| Über Dateisysteme | ❌ Nein |
| Auf Verzeichnisse | ❌ Nein (außer . und ..) |
| Eigene Inode | ❌ Nein (teilt Inode) |
| Erkennung | Link-Count > 1 |
Einschränkungen unter macOS:
# Harte Links auf Verzeichnisse sind nicht erlaubt
ln /Users/max/Documents /Users/max/Docs
# ln: /Users/max/Documents: Is a directory
# Harte Links über Volumes hinweg nicht möglich
ln /Volumes/USB/file.txt ~/file.txt
# ln: /Volumes/USB/file.txt: Cross-device link
1.3 Unterschiede und Anwendungsfälle
Vergleichstabelle:
| Merkmal | Symbolischer Link | Harter Link |
|---|---|---|
| Verweist auf | Pfadname | Inode |
| Eigene Inode | Ja | Nein |
| Funktioniert nach Löschen des Originals | Nein (broken) | Ja |
| Über Dateisysteme | Ja | Nein |
| Auf Verzeichnisse | Ja | Nein |
| Platzbedarf | Minimal (Pfad) | Keiner (Eintrag) |
| Typische Nutzung | Verknüpfungen, Aliase | Backups, Deduplizierung |
Wann Symlinks verwenden:
- Verknüpfungen zu Verzeichnissen
- Links über verschiedene Volumes/Partitionen
- Wenn der Link als “Verweis” erkennbar sein soll
- Konfigurationsdateien an mehreren Orten verfügbar machen
- Versionierte Verzeichnisse (z.B.
current -> v2.1.0)
Wann harte Links verwenden:
- Backup-Systeme (Time Machine nutzt harte Links)
- Deduplizierung von Dateien
- Wenn die Datei auch nach Löschen des “Originals” erhalten bleiben soll
- Space-effiziente Kopien
Beispiel: Versionierung mit Symlinks:
# Versionen als Verzeichnisse
mkdir -p ~/apps/myapp-1.0.0 ~/apps/myapp-1.1.0 ~/apps/myapp-2.0.0
# Symlink auf aktuelle Version
ln -s ~/apps/myapp-2.0.0 ~/apps/myapp-current
# Update auf neue Version
rm ~/apps/myapp-current
ln -s ~/apps/myapp-2.1.0 ~/apps/myapp-current
# Oder mit ln -sf (force)
ln -sf ~/apps/myapp-2.1.0 ~/apps/myapp-current
1.4 Links verwalten (readlink, unlink)
readlink – Linkziel auslesen:
# Symlink-Ziel anzeigen
readlink ~/Projekte
# Dropbox/Projekte
# Kanonischen (absoluten) Pfad auflösen
readlink -f ~/Projekte
# /Users/max/Dropbox/Projekte
# Auch für nicht existierende Pfade
readlink -f ./relative/path/../file.txt
# /Users/max/current/file.txt
Optionen:
| Option | Beschreibung |
|---|---|
-f | Kanonischer Pfad (alle Symlinks auflösen) |
-n | Keine Newline am Ende |
unlink – Link entfernen:
# Symlink entfernen (nicht das Ziel!)
unlink ~/Projekte
# Äquivalent zu rm für einzelne Dateien
rm ~/Projekte
caution
Bei Verzeichnis-Symlinks keinen Trailing Slash verwenden!
# RICHTIG: Entfernt den Symlink
rm ~/Projekte
# FALSCH: Versucht Inhalt des Zielverzeichnisses zu löschen!
rm -r ~/Projekte/
Der Trailing Slash (/) bewirkt, dass die Shell den Symlink auflöst und dem Befehl das Zielverzeichnis übergibt. Mit rm -r ~/Projekte/ löscht man daher nicht den Symlink, sondern den Inhalt des verlinkten Verzeichnisses – ein häufiger und folgenschwerer Fehler.
Links finden:
# Alle Symlinks in einem Verzeichnis
find ~/Documents -type l
# Broken Symlinks finden
find ~/Documents -type l ! -exec test -e {} \; -print
# Alle harten Links zu einer Datei finden (gleiche Inode)
find / -inum $(stat -f %i datei.txt) 2>/dev/null
Link-Informationen mit stat:
# Inode und Link-Count anzeigen
stat -f "Inode: %i, Links: %l" datei.txt
# Bei Symlinks: Link vs. Ziel
stat -f "Link: %N, Ziel: %Y" ~/Projekte
2 Dateisystem-Tools
2.1 stat – Detaillierte Datei-Informationen
stat zeigt umfassende Metadaten einer Datei an.
Syntax:
stat [Optionen] DATEI
Standardausgabe:
stat ~/.zshrc
# 16777220 8453123 -rw-r--r-- 1 max staff 0 2048 "Jan 15 10:30:00 2024" ...
Formatierte Ausgabe (macOS BSD-stat):
# Lesbare Ausgabe
stat -x ~/.zshrc
# Bestimmte Felder
stat -f "%N: %z Bytes, modified %Sm" ~/.zshrc
# .zshrc: 2048 Bytes, modified Jan 15 10:30:00 2024
# Nur Dateigröße
stat -f %z ~/.zshrc
# 2048
# Nur Inode
stat -f %i ~/.zshrc
# 8453123
# Berechtigungen oktal
stat -f %Op ~/.zshrc
# 100644
# Besitzer und Gruppe
stat -f "%Su:%Sg" ~/.zshrc
# max:staff
Format-Spezifizierer (BSD/macOS):
| Spezifizierer | Beschreibung |
|---|---|
%N | Dateiname |
%z | Größe in Bytes |
%i | Inode-Nummer |
%l | Anzahl harter Links |
%Op | Berechtigungen (oktal) |
%Sp | Berechtigungen (symbolisch) |
%Su | Besitzer (Name) |
%Sg | Gruppe (Name) |
%u | Besitzer (UID) |
%g | Gruppe (GID) |
%Sa | Zugriffszeit |
%Sm | Änderungszeit |
%Sc | Statusänderungszeit |
%SB | Erstellungszeit (macOS) |
%Y | Symlink-Ziel |
%T | Dateityp |
Beispiele:
# Erstellungsdatum (macOS-spezifisch)
stat -f "Erstellt: %SB" -t "%Y-%m-%d %H:%M" ~/.zshrc
# Vergleich zweier Dateien
for f in file1.txt file2.txt; do
stat -f "%N: %z Bytes, %Sm" "$f"
done
# Alle Infos für Skript
stat -f "size=%z;inode=%i;mode=%Op;uid=%u;gid=%g" datei.txt
2.2 file – Dateityp erkennen
file analysiert den Inhalt einer Datei und bestimmt ihren Typ – unabhängig von der Dateiendung.
Syntax:
file [Optionen] DATEI...
Beispiele:
file document.pdf
# document.pdf: PDF document, version 1.7
file image.png
# image.png: PNG image data, 1920 x 1080, 8-bit/color RGBA
file script.sh
# script.sh: Bourne-Again shell script, ASCII text executable
file binary
# binary: Mach-O 64-bit executable arm64
file archive.tar.gz
# archive.tar.gz: gzip compressed data
file unknown
# unknown: ASCII text, with very long lines
Optionen:
| Option | Beschreibung |
|---|---|
-b | Brief: Kein Dateiname in Ausgabe |
-i | MIME-Typ ausgeben |
-I | MIME-Typ mit Encoding |
-L | Symlinks folgen |
-z | Komprimierte Dateien untersuchen |
Anwendungen:
# MIME-Typ für Webserver
file -I document.pdf
# document.pdf: application/pdf; charset=binary
# Mehrere Dateien
file *
# bild.jpg: JPEG image data
# script.py: Python script, ASCII text
# data.json: JSON data
# In Skripten: Typ prüfen
if file -b "$1" | grep -q "shell script"; then
echo "Ist ein Shell-Skript"
fi
# Nur echte Bilder finden
find . -type f -exec file {} \; | grep "image data"
2.3 mdls – macOS-Metadaten anzeigen
mdls zeigt Spotlight-Metadaten einer Datei an. Diese umfassen weit mehr als Standard-Dateiattribute.
Syntax:
mdls [Optionen] DATEI
Beispiel:
mdls foto.jpg
# kMDItemContentType = "public.jpeg"
# kMDItemContentTypeTree = (
# "public.jpeg",
# "public.image",
# "public.data"
# )
# kMDItemDateTimeOriginal = 2024-01-15 10:30:00 +0000
# kMDItemPixelHeight = 1080
# kMDItemPixelWidth = 1920
# kMDItemColorSpace = "RGB"
# ...
Bestimmte Attribute abfragen:
# Nur bestimmtes Attribut
mdls -name kMDItemContentType foto.jpg
# kMDItemContentType = "public.jpeg"
# Mehrere Attribute
mdls -name kMDItemPixelWidth -name kMDItemPixelHeight foto.jpg
# Wert ohne Attributnamen
mdls -raw -name kMDItemPixelWidth foto.jpg
# 1920
Wichtige Metadaten-Attribute:
| Attribut | Beschreibung |
|---|---|
kMDItemContentType | UTI-Dateityp |
kMDItemKind | Lesbare Typbeschreibung |
kMDItemFSName | Dateiname |
kMDItemFSSize | Dateigröße |
kMDItemFSCreationDate | Erstellungsdatum |
kMDItemContentCreationDate | Inhalt erstellt |
kMDItemContentModificationDate | Inhalt geändert |
kMDItemPixelWidth/Height | Bildgröße |
kMDItemDurationSeconds | Medien-Dauer |
kMDItemTitle | Titel |
kMDItemAuthors | Autoren |
kMDItemWhereFroms | Download-URL |
Praktische Beispiele:
# Bildabmessungen
mdls -name kMDItemPixelWidth -name kMDItemPixelHeight *.jpg
# Woher wurde Datei heruntergeladen?
mdls -name kMDItemWhereFroms ~/Downloads/installer.dmg
# Dauer eines Videos
mdls -raw -name kMDItemDurationSeconds video.mp4
# Alle PDFs mit Seitenzahl
for f in *.pdf; do
pages=$(mdls -raw -name kMDItemNumberOfPages "$f" 2>/dev/null)
echo "$f: $pages Seiten"
done
Metadaten setzen mit xattr:
# Extended Attributes anzeigen
xattr -l datei.txt
# Quarantäne-Flag entfernen (heruntergeladene Dateien)
xattr -d com.apple.quarantine datei.app
# Alle xattrs entfernen
xattr -c datei.txt
3 Volumes & Mounten
3.1 diskutil – Laufwerke verwalten
diskutil ist das zentrale macOS-Tool zur Verwaltung von Festplatten, Partitionen und Volumes.
Laufwerke auflisten:
# Alle Laufwerke
diskutil list
# Ausgabe:
# /dev/disk0 (internal, physical):
# #: TYPE NAME SIZE
# 0: GUID_partition_scheme *500.1 GB
# 1: EFI EFI 209.7 MB
# 2: Apple_APFS Container disk1 499.9 GB
#
# /dev/disk1 (synthesized):
# #: TYPE NAME SIZE
# 0: APFS Container Scheme - +499.9 GB
# 1: APFS Volume Macintosh HD 12.4 GB
# 2: APFS Volume Preboot 23.1 MB
# ...
Volume-Informationen:
# Detaillierte Infos zu einem Volume
diskutil info /dev/disk1s1
# Infos über Mount-Point
diskutil info /Volumes/USB
# Nur bestimmte Info
diskutil info /dev/disk1s1 | grep "Volume Name"
Volumes ein- und aushängen:
# Volume aushängen
diskutil unmount /Volumes/USB
diskutil unmount /dev/disk2s1
# Volume einhängen
diskutil mount /dev/disk2s1
# Alle Volumes eines Laufwerks aushängen
diskutil unmountDisk /dev/disk2
# Laufwerk sicher auswerfen
diskutil eject /dev/disk2
Partitionen und Formatierung:
# Volume löschen (APFS)
diskutil eraseVolume APFS "NeuesVolume" /dev/disk2s1
# Ganzes Laufwerk formatieren (ACHTUNG!)
diskutil eraseDisk APFS "MeinDisk" /dev/disk2
# Verfügbare Dateisystem-Typen
diskutil listFilesystems
# Partition hinzufügen (APFS Container)
diskutil apfs addVolume disk1 APFS "Daten"
APFS-spezifische Befehle:
# APFS Container auflisten
diskutil apfs list
# Volume zu Container hinzufügen
diskutil apfs addVolume disk1 APFS "NeuesVolume"
# Volume löschen
diskutil apfs deleteVolume disk1s3
# Volume umbenennen
diskutil rename disk1s2 "Neuer Name"
Festplatten reparieren:
# Dateisystem prüfen
diskutil verifyVolume /dev/disk1s1
# Dateisystem reparieren
diskutil repairVolume /dev/disk1s1
# First Aid (GUI-Äquivalent)
diskutil verifyDisk /dev/disk0
diskutil repairDisk /dev/disk0
3.2 mount / umount – Volumes ein-/aushängen
Die klassischen Unix-Befehle mount und umount funktionieren auch unter macOS.
Aktuelle Mounts anzeigen:
# Alle gemounteten Volumes
mount
# Nur bestimmter Typ
mount | grep apfs
mount | grep nfs
# Übersichtlicher mit df
df -h
Volume manuell mounten:
# Mount-Point erstellen
sudo mkdir /Volumes/MeinUSB
# Volume mounten
sudo mount -t msdos /dev/disk2s1 /Volumes/MeinUSB
# Mit Optionen
sudo mount -t hfs -o ro /dev/disk2s1 /Volumes/ReadOnly
Volume aushängen:
# Normal aushängen
sudo umount /Volumes/MeinUSB
# Erzwingen (wenn "busy")
sudo umount -f /Volumes/MeinUSB
# Besser: diskutil verwenden
diskutil unmount /Volumes/MeinUSB
Mount-Optionen:
| Option | Beschreibung |
|---|---|
-t TYPE | Dateisystem-Typ (apfs, hfs, msdos, ntfs, nfs, smbfs) |
-o ro | Read-only |
-o rw | Read-write |
-o noexec | Keine Ausführung erlauben |
-o nosuid | Setuid ignorieren |
3.3 Netzlaufwerke mounten (SMB, NFS, AFP)
SMB/CIFS (Windows-Freigaben):
# Mit mount_smbfs
mount_smbfs //user@server/share /Volumes/Share
# Mit Passwort (unsicher, besser Keychain nutzen)
mount_smbfs //user:passwort@server/share /Volumes/Share
# Über Finder-URL (öffnet Finder)
open smb://server/share
# Mount-Point vorbereiten
mkdir -p /Volumes/NAS
mount_smbfs //max@nas.local/Daten /Volumes/NAS
NFS:
# NFS-Mount
sudo mount -t nfs server:/export/share /Volumes/NFS
# Mit Optionen
sudo mount -t nfs -o resvport,rw server:/share /Volumes/NFS
# NFS-Exports auf Server anzeigen
showmount -e server
AFP (Apple Filing Protocol, veraltet):
# AFP-Mount
mount_afp afp://user@server/share /Volumes/AFP
# Über Finder
open afp://server/share
WebDAV:
# WebDAV mounten
mount_webdav https://server/dav /Volumes/WebDAV
Netzlaufwerk per Skript verbinden:
#!/bin/zsh
# mount-nas.sh
SERVER="nas.local"
SHARE="Daten"
USER="max"
MOUNTPOINT="/Volumes/NAS"
# Mount-Point erstellen falls nötig
[-d "$MOUNTPOINT"](-d%20"$MOUNTPOINT".md) || mkdir -p "$MOUNTPOINT"
# Prüfen ob bereits gemountet
if mount | grep -q "$MOUNTPOINT"; then
echo "Bereits verbunden"
exit 0
fi
# Mounten (Passwort aus Keychain)
mount_smbfs "//${USER}@${SERVER}/${SHARE}" "$MOUNTPOINT"
if [$? -eq 0]($?%20-eq%200.md); then
echo "Erfolgreich verbunden: $MOUNTPOINT"
else
echo "Fehler beim Verbinden"
exit 1
fi
3.4 /etc/fstab – Automatisches Mounten
Die Datei /etc/fstab definiert Volumes, die beim Systemstart automatisch gemountet werden.
Syntax:
DEVICE MOUNTPOINT FSTYPE OPTIONS DUMP PASS
Beispiele:
# /etc/fstab bearbeiten
sudo nano /etc/fstab
# NFS-Share beim Start mounten
server:/export/data /Volumes/Data nfs rw,resvport 0 0
# SMB-Share (mit Benutzername)
//user@server/share /Volumes/Share smbfs -N 0 0
# USB-Laufwerk nach UUID
UUID=1234-5678 /Volumes/USB msdos rw 0 0
# Volume read-only mounten
LABEL=Backup /Volumes/Backup apfs ro 0 0
UUID ermitteln:
diskutil info /dev/disk2s1 | grep "Volume UUID"
fstab neu einlesen:
sudo automount -vc
note
macOS verwendet primär /etc/auto_master für Automounts. Für Netzlaufwerke ist oft ein Login-Item oder launchd-Job praktischer.
Automatisches Mounten mit launchd:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>com.user.mount-nas</string>
<key>ProgramArguments</key>
<array>
<string>/usr/bin/mount_smbfs</string>
<string>//user@server/share</string>
<string>/Volumes/NAS</string>
</array>
<key>RunAtLoad</key>
<true/>
<key>WatchPaths</key>
<array>
<string>/etc/resolv.conf</string>
</array>
</dict>
</plist>
4 Disk Images & Sparse Files
Disk Images sind Container-Dateien, die ein virtuelles Dateisystem enthalten. Unter macOS sind sie allgegenwärtig für Software-Verteilung, verschlüsselte Container und Backups.
Typen von Disk Images:
| Typ | Endung | Beschreibung |
|---|---|---|
| Read-only | .dmg | Komprimiert, nicht veränderbar |
| Read/write | .dmg | Veränderbar, feste Größe |
| Sparse | .sparseimage | Wächst bei Bedarf |
| Sparse Bundle | .sparsebundle | Wächst, besteht aus Bändern |
| DVD/CD Master | .cdr | Für Brennen |
Sparse Files:
Ein Sparse File belegt nur so viel Platz wie tatsächlich geschriebene Daten:
# Sparse File erstellen (10GB logisch, 0 Bytes real)
dd if=/dev/zero of=sparse.img bs=1 count=0 seek=10G
# Tatsächliche vs. logische Größe
ls -lh sparse.img # zeigt 10G
du -h sparse.img # zeigt 0B (oder wenige KB)
# Mit stat
stat -f "Logisch: %z, Blöcke: %b" sparse.img
5 Erweiterte Datei- und Backupwerkzeuge
In diesem Kapitel geht es um Befehle, mit denen man ganze Verzeichnisse oder Datenbestände effizient kopieren, klonen oder synchronisieren kannst.
Während einfache Kopierbefehle wie cp für einzelne Dateien ausreichen, sind ditto und rsync leistungsfähige Werkzeuge für komplexere Aufgaben, wie beispielsweise die Erstellung von Backups, der Übertragung großer Datenmengen oder beim der Spiegelung von Ordnern inklusive Berechtigungen, Metadaten und versteckten Dateien.
5.1 cp – Der klassische Kopierbefehl
cp ist der einfachste Befehl zum Kopieren von Dateien oder Verzeichnissen. Mit der Option -R (rekursiv) kopiert er auch Unterordner.
Beispiel:
cp -R Quelle Ziel
Verwendung:
Für schnelle, einfache Kopiervorgänge, etwa einzelne Dateien oder kleine Ordner.
Vorteile:
- immer verfügbar, sehr einfach
- Schnell bei wenigen Dateien
Nachteile:
- Keine Fortschrittsanzeige
- Keine Synchronisation
- Kopiert oft keine versteckten Metadaten
- Keine Option zum Erstellen von Archiven
5.2 ditto – Systemgerechtes Kopieren und Archivieren
Mit dem Befehl ditto werden Verzeichnisse kopiert/dupliziert.
note
Im Gegensatz zu cp kann ditto Ressourcendateien, Metadaten, Rechte, unsichtbare Dateien und Paketstrukturen (z. B. App-Bundles) korrekt handhaben.
Syntax:
ditto [Optionen] Quelle Ziel
Verwendung:
Ideal zum Klonen von Projekten, App-Bundles oder Backups auf demselben System. Auch nützlich zum Erstellen von ZIP-Archiven mit -c -k.
Vorteile:
- Bewahrt Metadaten, ACLs, Ressourcen
- Zusammenführen statt stumpfem Überschreiben
- Kann ZIP-Archive erstellen
- macOS-optimiert
Nachteile:
- Arbeitet nur lokal (kein Netzwerktransfer)
- Weniger effizient bei großen oder häufigen Synchronisationen
5.2.1 Beispiele
Ordner vollständig kopieren (inklusive versteckter Dateien wie .DS_Store und .git):
ditto ~/Projekte/ProjektA ~/Backup/ProjektA
Eine App korrekt klonen (inkl. Metadaten):
sudo ditto /Applications/App.app /Applications/App-Kopie.app
Nur neue oder geänderte Dateien kopieren:
ditto --update ~/Projekte/ ~/Backup/Projekte/
Eine ZIP-Datei aus einem Ordner erzeugen:
ditto -c -k --sequesterRsrc --keepParent "MeinOrdner" "MeinOrdner.zip"
→ Erstellt ein ZIP-Archiv, das auch Ressourcendateien und Metadaten beibehält.
5.2.2 Häufige Optionen
| Option | Bedeutung |
|---|---|
--update | Nur neuere Dateien kopieren |
--norsrc | Ressourcen-Forks nicht mitkopieren |
--rsrc | Ressourcen-Forks mitkopieren (Standardverhalten) |
-V | Zeigt detaillierte Ausgaben (Verbose-Modus) |
-X | Bewahrt erweiterte Attribute (ACLs, Metadaten) |
-c -k | Erstellt ein ZIP-Archiv |
--sequesterRsrc --keepParent | Erhält Ressourcen und übergeordnete Ordnerstruktur beim Archivieren |
5.2.3 Typische Anwendungsfälle
- Vollständige Kopien von App-Bundles, Projekten oder Verzeichnissen unter Beibehaltung macOS-spezifischer Dateiattribute (z. B. ACLs, HFS+ Metadaten)
- Erstellung von Backups und ZIP-Archiven
- Zusammenführen von Ordnern mit Erhalt von Metadaten
- Alternative zu
cp -Rmit besserer macOS-Kompatibilität - Installer-Skripte und Backup-Tools
5.3 rsync – Effiziente Synchronisation und Spiegelung
Der Befehl rsync wird verwendet, um Dateien und Verzeichnisse effizient zu synchronisieren – lokal oder über ein Netzwerk. Er überträgt nur geänderte Teile von Dateien, was ihn besonders schnell und bandbreitenschonend macht. rsync ist ideal für Backups, Spiegelungen und regelmäßige Synchronisationen zwischen Verzeichnissen oder Rechnern.
Syntax:
rsync [Optionen] Quelle Ziel
Verwendung:
Für effiziente Backups, Netzwerkübertragungen und automatisierte Synchronisationen.
Vorteile:
- Überträgt nur geänderte Dateien → sehr schnell bei Wiederholungen
- Netzwerkfähig (via SSH)
- Fortschrittsanzeige, Testlauf-Modus (-n)
- Ideal für Skripte und Automatisierung
Nachteile:
- Etwas komplexer in der Handhabung
- Irrtümlich gesetzte Optionen (z. B.
--delete) können Daten löschen - Nicht alle macOS-spezifischen Metadaten werden immer exakt kopiert
5.3.1 Beispiele
Einen Ordner lokal synchronisieren:
rsync -av ~/Projekte/MeinApp/ ~/Backup/MeinApp/
→ Kopiert alle Dateien und Unterordner, behält Berechtigungen und Zeiten bei, synchronisiert nur geänderte Dateien.
Dateien auf einen anderen Rechner übertragen:
rsync -avz ~/Projekte/MeinApp/ user@server:/Users/user/Backup/MeinApp/
→ Überträgt den Ordner über SSH auf einen entfernten Rechner. Die Option -z komprimiert die Daten während der Übertragung.
Nur geänderte Dateien aktualisieren:
rsync -avu ~/Projekte/MeinApp/ ~/Backup/MeinApp/
→ Die Option -u sorgt dafür, dass nur neuere Dateien kopiert werden.
Dateien löschen, die im Ziel nicht mehr existieren:
rsync -av --delete ~/Projekte/MeinApp/ ~/Backup/MeinApp/
→ Hält das Zielverzeichnis exakt synchron mit der Quelle (Achtung: löscht zusätzliche Dateien im Ziel!).
5.3.2 Häufige Optionen
| Option | Beschreibung |
|---|---|
-n | “Testlauf” – zeigt, was passieren würde, ohne Änderungen vorzunehmen |
-a | Archivmodus: kopiert rekursiv und bewahrt Berechtigungen, Zeiten und Symlinks |
-v | Verbose: zeigt detaillierte Fortschrittsinformationen |
-z | Komprimiert Daten während der Übertragung |
-u | Überspringt Dateien, die im Ziel neuer sind |
--delete | Löscht Dateien im Ziel, die in der Quelle nicht mehr existieren |
--progress | Zeigt den Fortschritt jeder Dateiübertragung |
-e ssh | Erzwingt die Verwendung von SSH (meist automatisch aktiv) |
5.3.3 Typische Anwendungsfälle
- Erstellung und Aktualisierung von Backups´
- Synchronisation zwischen zwei Festplatten oder Rechnern
- Spiegelung von Verzeichnisstrukturen auf Servern
- Automatisierte Sicherungsskripte (z. B. via
cron) - Übertragung großer Datenmengen mit minimaler Redundanz
5.4 Vergleich: cp, ditto und rsync
Es gibt mehrere Befehle, um Dateien und Ordner zu kopieren oder zu sichern. Die drei wichtigsten sind cp, ditto und rsync. Obwohl sie ähnliche Aufgaben erfüllen, unterscheiden sie sich deutlich in Funktionsumfang, Zuverlässigkeit und Einsatzgebiet.
| Merkmal | cp | ditto | rsync |
|---|---|---|---|
| Kopiert Verzeichnisse rekursiv | ✅ (-R) | ✅ | ✅ |
| Bewahrt Metadaten / ACLs | ⚠️ Teilweise | ✅ Vollständig | ⚠️ Teilweise |
| Versteckte Dateien (.git, .DS_Store) | ❌ Nicht immer | ✅ | ✅ |
| Nur geänderte Dateien kopieren | ❌ | ❌ | ✅ |
| Fortschrittsanzeige | ❌ | ⚠️ (mit -V) | ✅ (--progress) |
| Zusammenführen statt Überschreiben | ❌ | ✅ | ✅ |
| Erstellung von Archiven (ZIP etc.) | ❌ | ✅ (-c -k) | ❌ |
| Netzwerkfähig | ❌ | ❌ | ✅ (SSH) |
| Skript-/Backup-tauglich | ⚠️ Einfach | ✅ Lokal | ✅ Sehr gut |
| Komplexität | ⭐ Einfach | ⭐⭐ Mittel | ⭐⭐⭐ Anspruchsvoll |
cp: Für einfache, schnelle Kopien – ideal bei Einzeldaten.ditto: Für vollständige, macOS-gerechte Kopien und Archive.rsync: Für effiziente, wiederholbare Backups und Synchronisationen – auch über Netzwerke.
5.5 hdiutil – Disk Images erstellen und verwalten
hdiutil ist das mächtige Kommandozeilen-Tool für alle Disk-Image-Operationen unter macOS.
Image erstellen:
# Leeres DMG (100 MB, HFS+)
hdiutil create -size 100m -fs HFS+ -volname "MeinVolume" MeinImage.dmg
# APFS-Image
hdiutil create -size 100m -fs APFS -volname "MeinVolume" MeinImage.dmg
# Aus Ordner erstellen
hdiutil create -srcfolder ~/MeinOrdner -volname "Backup" Backup.dmg
# Mit Komprimierung
hdiutil create -srcfolder ~/MeinOrdner -format UDZO -volname "Backup" Backup.dmg
Image-Formate:
| Format | Code | Beschreibung |
|---|---|---|
| Read/write | UDRW | Veränderbar |
| Compressed | UDZO | zlib-komprimiert, read-only |
| LZMA compressed | ULMO | Stark komprimiert |
| Sparse | UDSP | Wachsend, veränderbar |
| Sparse bundle | UDSB | Band-basiert, wachsend |
| DVD/CD Master | UDTO | Für Brennen |
Image mounten:
# Standard-Mount (im Finder sichtbar)
hdiutil attach MeinImage.dmg
# Mount ohne Finder-Fenster
hdiutil attach MeinImage.dmg -nobrowse
# Mount an bestimmtem Punkt
hdiutil attach MeinImage.dmg -mountpoint /Volumes/MeinMount
# Read-only mounten
hdiutil attach MeinImage.dmg -readonly
# Ohne Verifizierung (schneller)
hdiutil attach MeinImage.dmg -noverify
Image aushängen:
# Nach Volume-Name
hdiutil detach /Volumes/MeinVolume
# Erzwingen
hdiutil detach /Volumes/MeinVolume -force
# Alle Images aushängen
hdiutil detach -all
Image konvertieren:
# Zu komprimiertem Read-only
hdiutil convert original.dmg -format UDZO -o komprimiert.dmg
# Zu read/write
hdiutil convert readonly.dmg -format UDRW -o readwrite.dmg
# Zu Sparse Bundle
hdiutil convert original.dmg -format UDSB -o sparse.sparsebundle
Image-Größe ändern:
# Größe erweitern (nur sparse/read-write)
hdiutil resize -size 200m MeinImage.dmg
# Auf minimale Größe schrumpfen
hdiutil resize -size min MeinImage.dmg
# Um Betrag erweitern
hdiutil resize -growonly -size 100m MeinImage.dmg
Image-Informationen:
# Image-Info anzeigen
hdiutil imageinfo MeinImage.dmg
# Nur Format
hdiutil imageinfo -format MeinImage.dmg
# Prüfsumme verifizieren
hdiutil verify MeinImage.dmg
5.6 Sparse Images und Sparse Bundles
Sparse Images wachsen dynamisch und belegen nur so viel Platz wie der tatsächliche Inhalt.
Sparse Image erstellen:
# Sparse Image (max 50 GB, wächst bei Bedarf)
hdiutil create -size 50g -type SPARSE -fs APFS -volname "Daten" Daten.sparseimage
# Sparse Bundle (bessere Performance bei Time Machine/Netzwerk)
hdiutil create -size 50g -type SPARSEBUNDLE -fs APFS -volname "Daten" Daten.sparsebundle
Unterschied Sparse Image vs. Sparse Bundle:
| Merkmal | Sparse Image | Sparse Bundle |
|---|---|---|
| Dateistruktur | Eine Datei | Ordner mit Bändern |
| Backup-freundlich | ❌ Ganze Datei | ✅ Nur geänderte Bänder |
| Time Machine | Nicht optimal | Empfohlen |
| Netzwerk | Langsam | Schneller |
| Kompaktieren | Möglich | Möglich |
Sparse Bundle Struktur:
ls Daten.sparsebundle/
# Info.plist
# bands/
# 0
# 1
# 2
# ...
# token
Größe kompaktieren (ungenutzten Platz freigeben):
# Erst aushängen
hdiutil detach /Volumes/Daten
# Kompaktieren
hdiutil compact Daten.sparsebundle
# Oder für Sparse Image
hdiutil compact Daten.sparseimage
Bandgröße für Sparse Bundle festlegen:
# 8 MB Bänder (Standard)
hdiutil create -size 50g -type SPARSEBUNDLE -fs APFS \
-imagekey sparse-band-size=16384 \
-volname "Daten" Daten.sparsebundle
# sparse-band-size ist in 512-Byte-Sektoren
# 16384 * 512 = 8 MB
# 131072 * 512 = 64 MB
5.7 Verschlüsselte Disk Images
Disk Images können mit AES-128 oder AES-256 verschlüsselt werden – ideal für sensible Daten.
Verschlüsseltes Image erstellen:
# AES-256 (empfohlen)
hdiutil create -size 100m -fs APFS -volname "Geheim" \
-encryption AES-256 -stdinpass Geheim.dmg
# Passwort eingeben...
# AES-128 (schneller)
hdiutil create -size 100m -fs APFS -volname "Geheim" \
-encryption AES-128 Geheim.dmg
# Aus Ordner mit Verschlüsselung
hdiutil create -srcfolder ~/Vertraulich \
-encryption AES-256 -format UDZO \
-volname "Vertraulich" Vertraulich.dmg
Verschlüsseltes Sparse Bundle (empfohlen für wachsende Daten):
hdiutil create -size 10g -type SPARSEBUNDLE -fs APFS \
-encryption AES-256 -volname "Tresor" Tresor.sparsebundle
Verschlüsseltes Image mounten:
# Passwort-Abfrage
hdiutil attach Geheim.dmg
# Passwort in Keychain speichern (beim ersten Mount)
# → Option im Dialog wählen
# Passwort per stdin
echo -n "geheim123" | hdiutil attach Geheim.dmg -stdinpass
Passwort ändern:
hdiutil chpass Geheim.dmg
# Altes Passwort eingeben
# Neues Passwort eingeben
Bestehendes Image verschlüsseln:
# Konvertieren mit Verschlüsselung
hdiutil convert Unverschluesselt.dmg \
-format UDZO -encryption AES-256 \
-o Verschluesselt.dmg
Sicherheits-Best-Practices:
- AES-256 für sensitive Daten verwenden
- Starkes Passwort wählen (Passphrase)
- Passwort nicht im Schlüsselbund speichern für höchste Sicherheit
- Image nach Gebrauch aushängen
- Bei Sparse Bundles: Nach Löschen von Dateien kompaktieren
5.8 DMG-Dateien per Terminal
DMG aus Ordner erstellen (App-Verteilung):
# Einfaches DMG
hdiutil create -srcfolder MeinApp.app \
-volname "MeinApp" \
-format UDZO \
MeinApp.dmg
# Mit Hintergrundbild und Icon-Positionen
# (Erfordert erst ein Read/Write Image)
hdiutil create -srcfolder MeinApp.app \
-volname "MeinApp" \
-format UDRW \
-fs HFS+ \
temp.dmg
# Mounten und anpassen
hdiutil attach temp.dmg
# Finder-Einstellungen setzen (AppleScript oder manuell)
# ...
# Zu komprimiertem DMG konvertieren
hdiutil convert temp.dmg -format UDZO -o MeinApp.dmg
rm temp.dmg
Internet-Enabled DMG (automatisches Entpacken):
hdiutil internet-enable -yes MeinApp.dmg
DMG verifizieren:
# Prüfsumme verifizieren
hdiutil verify MeinApp.dmg
# Inhalt auflisten ohne Mounten
hdiutil imageinfo MeinApp.dmg
DMG in ISO konvertieren:
hdiutil convert original.dmg -format UDTO -o converted.cdr
mv converted.cdr converted.iso
ISO/CDR erstellen:
# Aus Ordner
hdiutil makehybrid -iso -joliet -o output.iso source_folder/
# CD/DVD-Master für Brennen
hdiutil create -srcfolder Daten -format UDTO -o Master.cdr
Bootfähiges USB-Medium erstellen:
# macOS-Installer auf USB
sudo /Applications/Install\ macOS\ Sonoma.app/Contents/Resources/createinstallmedia \
--volume /Volumes/USB
# Alternativ mit dd (für Linux ISOs etc.)
diskutil unmountDisk /dev/disk2
sudo dd if=linux.iso of=/dev/rdisk2 bs=1m
diskutil eject /dev/disk2
Praktische Aliase:
# ~/.zshrc
# DMG schnell erstellen
dmg-create() {
local src="$1"
local name="${2:-${src:t}}"
hdiutil create -srcfolder "$src" -volname "$name" -format UDZO "${name}.dmg"
}
# Verschlüsseltes Sparse Bundle erstellen
vault-create() {
local name="$1"
local size="${2:-10g}"
hdiutil create -size "$size" -type SPARSEBUNDLE -fs APFS \
-encryption AES-256 -volname "$name" "${name}.sparsebundle"
}
# DMG schnell mounten
alias dmg-mount='hdiutil attach'
alias dmg-unmount='hdiutil detach'
Cheatsheet hdiutil:
# Erstellen
hdiutil create -size 100m -fs APFS -volname NAME out.dmg
hdiutil create -srcfolder ORDNER -format UDZO out.dmg
hdiutil create -size 10g -type SPARSEBUNDLE -encryption AES-256 out.sparsebundle
# Mounten
hdiutil attach image.dmg
hdiutil attach image.dmg -mountpoint /Volumes/MOUNT
hdiutil attach image.dmg -readonly
# Aushängen
hdiutil detach /Volumes/NAME
# Konvertieren
hdiutil convert in.dmg -format UDZO -o out.dmg
hdiutil convert in.dmg -format UDRW -o out.dmg
# Größe ändern
hdiutil resize -size 200m image.sparseimage
hdiutil compact image.sparsebundle
# Info
hdiutil imageinfo image.dmg
hdiutil verify image.dmg
Netzwerk (erweitert)
Dieses Kapitel behandelt fortgeschrittene Netzwerk-Tools für DNS-Analyse, Verbindungsdiagnose und Dateiübertragung.
1 DNS & Namensauflösung
DNS (Domain Name System) übersetzt Domainnamen in IP-Adressen. Die folgenden Tools helfen bei der Diagnose von DNS-Problemen.
1.1 nslookup – DNS-Abfragen
nslookup ist ein klassisches Tool für DNS-Abfragen, verfügbar auf praktisch allen Systemen.
Grundlegende Abfragen:
# Einfache Namensauflösung
nslookup example.com
# Server: 192.168.1.1
# Address: 192.168.1.1#53
#
# Non-authoritative answer:
# Name: example.com
# Address: 93.184.216.34
# IPv6-Adresse abfragen
nslookup -type=AAAA example.com
# Reverse-Lookup (IP → Name)
nslookup 8.8.8.8
# Name: dns.google
Bestimmten DNS-Server verwenden:
# Google DNS
nslookup example.com 8.8.8.8
# Cloudflare DNS
nslookup example.com 1.1.1.1
# Lokaler DNS
nslookup example.com 192.168.1.1
Record-Typen abfragen:
# MX-Records (Mail)
nslookup -type=MX example.com
# NS-Records (Nameserver)
nslookup -type=NS example.com
# TXT-Records (SPF, DKIM, etc.)
nslookup -type=TXT example.com
# SOA-Record (Start of Authority)
nslookup -type=SOA example.com
# CNAME-Record (Alias)
nslookup -type=CNAME www.example.com
# Alle Records
nslookup -type=ANY example.com
Interaktiver Modus:
nslookup
> server 8.8.8.8
> set type=MX
> example.com
> exit
Häufige Record-Typen:
| Typ | Beschreibung |
|---|---|
A | IPv4-Adresse |
AAAA | IPv6-Adresse |
MX | Mail-Server |
NS | Nameserver |
TXT | Text-Records (SPF, DKIM) |
CNAME | Alias/Weiterleitung |
SOA | Zonen-Autorität |
PTR | Reverse-Lookup |
SRV | Service-Records |
1.2 dig – Erweiterte DNS-Analyse
dig (Domain Information Groper) ist das mächtigste DNS-Tool mit detaillierten Ausgaben.
Installation (falls nicht vorhanden):
brew install bind # enthält dig
Grundlegende Abfragen:
# Standard-Abfrage
dig example.com
# Kurzform (nur Antwort)
dig +short example.com
# 93.184.216.34
# Bestimmter Record-Typ
dig example.com MX
dig example.com AAAA
dig example.com TXT
Ausgabe verstehen:
dig example.com
# ;; QUESTION SECTION:
# ;example.com. IN A
#
# ;; ANSWER SECTION:
# example.com. 86400 IN A 93.184.216.34
#
# ;; Query time: 23 msec
# ;; SERVER: 192.168.1.1#53(192.168.1.1)
| Sektion | Beschreibung |
|---|---|
| QUESTION | Gestellte Anfrage |
| ANSWER | Antwort-Records |
| AUTHORITY | Zuständige Nameserver |
| ADDITIONAL | Zusätzliche Infos |
| Query time | Antwortzeit |
| SERVER | Verwendeter DNS-Server |
Bestimmten DNS-Server verwenden:
# Mit @server
dig @8.8.8.8 example.com
dig @1.1.1.1 example.com +short
Erweiterte Optionen:
# Alle Sektionen anzeigen
dig example.com +all
# Nur Antwort-Sektion
dig example.com +noall +answer
# Ohne Kommentare
dig example.com +nocomments
# Mit Statistiken
dig example.com +stats
# Trace: Komplette DNS-Auflösung verfolgen
dig example.com +trace
# Reverse-Lookup
dig -x 8.8.8.8
Batch-Abfragen:
# Mehrere Domains
dig example.com google.com github.com +short
# Aus Datei
dig -f domains.txt +short
DNS-Propagation prüfen:
# Bei verschiedenen DNS-Servern abfragen
for dns in 8.8.8.8 1.1.1.1 9.9.9.9; do
echo "=== $dns ==="
dig @$dns example.com +short
done
Praktische Beispiele:
# SPF-Record prüfen
dig example.com TXT +short | grep spf
# Alle MX-Records mit Priorität
dig example.com MX +short
# 10 mail.example.com.
# 20 mail2.example.com.
# DNSSEC validieren
dig example.com +dnssec
# TTL (Time-to-Live) anzeigen
dig example.com | grep -A1 "ANSWER SECTION"
1.3 host – Einfache Namensauflösung
host bietet eine einfachere, lesbarere Ausgabe als dig.
Grundlegende Nutzung:
# Namensauflösung
host example.com
# example.com has address 93.184.216.34
# example.com has IPv6 address 2606:2800:220:1:248:1893:25c8:1946
# example.com mail is handled by 0 .
# Reverse-Lookup
host 8.8.8.8
# 8.8.8.8.in-addr.arpa domain name pointer dns.google.
Record-Typen:
# Nur bestimmten Typ
host -t MX example.com
host -t NS example.com
host -t TXT example.com
host -t AAAA example.com
DNS-Server angeben:
host example.com 8.8.8.8
Optionen:
| Option | Beschreibung |
|---|---|
-t TYPE | Record-Typ |
-a | Alle Record-Typen |
-v | Verbose (wie dig) |
-4 | Nur IPv4 |
-6 | Nur IPv6 |
Vergleich der DNS-Tools:
| Merkmal | nslookup | dig | host |
|---|---|---|---|
| Detailgrad | Mittel | Hoch | Niedrig |
| Lesbarkeit | Gut | Technisch | Sehr gut |
| Scripting | Möglich | Sehr gut | Gut |
| Verfügbarkeit | Überall | Meist installiert | Meist installiert |
| Empfehlung | Legacy | Experten | Schnelle Checks |
2 Verbindungen & Ports
2.1 netstat – Netzwerkstatistiken
netstat zeigt Netzwerkverbindungen, Routing-Tabellen und Interface-Statistiken.
tip
Unter macOS ist netstat verfügbar, aber lsof -i ist oft praktischer für Verbindungen. Es zeigt direkt den Prozessnamen und die PID zu jeder Verbindung, während netstat unter macOS diese Information nicht liefert. Außerdem bietet lsof flexiblere Filteroptionen nach Port, Protokoll und Prozess.
Aktive Verbindungen:
# Alle Verbindungen
netstat -an
# Nur TCP
netstat -an -p tcp
# Nur UDP
netstat -an -p udp
# Nur lauschende Ports
netstat -an | grep LISTEN
Ausgabe verstehen:
Proto Local Address Foreign Address State
tcp4 192.168.1.100.52341 93.184.216.34.443 ESTABLISHED
tcp4 *.80 *.* LISTEN
| Spalte | Beschreibung |
|---|---|
| Proto | Protokoll (tcp4, tcp6, udp) |
| Local Address | Lokale IP:Port |
| Foreign Address | Remote IP:Port |
| State | Verbindungsstatus |
Verbindungsstatus:
| Status | Beschreibung |
|---|---|
LISTEN | Wartet auf Verbindungen |
ESTABLISHED | Aktive Verbindung |
TIME_WAIT | Warten auf Timeout |
CLOSE_WAIT | Warten auf Schließen |
SYN_SENT | Verbindungsaufbau |
Routing-Tabelle:
netstat -rn
# Destination Gateway Flags
# default 192.168.1.1 UGSc
# 192.168.1.0/24 link#6 UCS
Interface-Statistiken:
# Alle Interfaces
netstat -i
# Mit Byte-Zählern
netstat -ib
# Bestimmtes Interface
netstat -I en0
Nützliche Kombinationen:
# Offene Ports nach Anzahl sortiert
netstat -an | grep ESTABLISHED | awk '{print $5}' | cut -d. -f1-4 | sort | uniq -c | sort -rn
# Verbindungen pro Status
netstat -an | awk '/^tcp/ {print $6}' | sort | uniq -c
# Lauschende Dienste
netstat -an -p tcp | grep LISTEN
2.2 lsof -i – Offene Netzwerkverbindungen
lsof (List Open Files) ist unter macOS das bevorzugte Tool für Netzwerkdiagnose.
Grundlegende Nutzung:
# Alle Netzwerkverbindungen
lsof -i
# Mit numerischen Ports (schneller)
lsof -i -n -P
Nach Port filtern:
# Bestimmter Port
lsof -i :80
lsof -i :443
lsof -i :3000
# Port-Bereich
lsof -i :8000-9000
# Mehrere Ports
lsof -i :80 -i :443
Nach Protokoll filtern:
# Nur TCP
lsof -i tcp
# Nur UDP
lsof -i udp
# Nur IPv4
lsof -i 4
# Nur IPv6
lsof -i 6
# Kombiniert
lsof -i tcp:443
Nach Prozess/Benutzer:
# Bestimmter Prozess
lsof -i -c nginx
lsof -i -c python
# Bestimmter Benutzer
lsof -i -u max
# Bestimmte PID
lsof -i -p 1234
Verbindungsstatus:
# Nur lauschende Ports
lsof -i -sTCP:LISTEN
# Nur etablierte Verbindungen
lsof -i -sTCP:ESTABLISHED
# Nur Verbindungen zu bestimmtem Host
lsof -i @192.168.1.100
lsof -i @google.com
Ausgabe verstehen:
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
nginx 1234 root 6u IPv4 0x1234 0t0 TCP *:http (LISTEN)
Chrome 5678 max 42u IPv4 0x5678 0t0 TCP 192.168.1.100:52341->93.184.216.34:https (ESTABLISHED)
| Spalte | Beschreibung |
|---|---|
| COMMAND | Programmname |
| PID | Prozess-ID |
| USER | Benutzer |
| FD | File Descriptor |
| TYPE | IPv4/IPv6 |
| NAME | Verbindungsdetails |
Praktische Beispiele:
# Was blockiert Port 8080?
lsof -i :8080
# Prozess auf Port beenden
kill $(lsof -t -i :8080)
# Alle Verbindungen eines Programms
lsof -i -c Chrome -n -P
# Verbindungen zu bestimmter Domain
lsof -i @github.com
# Lauschende Ports mit Prozessnamen
lsof -i -P -n | grep LISTEN
# Schnelle Übersicht
lsof -i -n -P | head -20
Aliase für häufige Abfragen:
# ~/.zshrc
alias ports='lsof -i -P -n | grep LISTEN'
alias conn='lsof -i -P -n'
alias whoport='lsof -i -P -n -sTCP:LISTEN | grep'
2.3 nc (netcat) – Netzwerk-Debugging
nc (netcat) ist das “Schweizer Taschenmesser” für Netzwerk-Debugging. Es kann Verbindungen öffnen, auf Ports lauschen und Daten übertragen.
Port-Scan:
# Einzelner Port
nc -zv host.com 80
# Connection to host.com port 80 [tcp/http] succeeded!
# Port-Bereich
nc -zv host.com 20-25
# Schneller Scan (ohne DNS)
nc -zv -n 192.168.1.1 22
# Mit Timeout
nc -zv -w 3 host.com 80
Port-Verfügbarkeit testen:
# HTTP-Port offen?
nc -zv google.com 80 443
# SSH erreichbar?
nc -zv -w 5 server.com 22
Auf Port lauschen (Server):
# Einfacher Server auf Port 1234
nc -l 1234
# Mit Verbose-Output
nc -lv 1234
# UDP-Server
nc -lu 1234
Verbindung herstellen (Client):
# Zu Server verbinden
nc host.com 1234
# Nachricht senden
echo "Hello" | nc host.com 1234
# HTTP-Request manuell
echo -e "GET / HTTP/1.1\r\nHost: example.com\r\n\r\n" | nc example.com 80
Dateiübertragung:
# Empfänger (lauscht)
nc -l 1234 > received_file.txt
# Sender
nc receiver.com 1234 < file.txt
# Mit Fortschritt (via pv)
pv file.txt | nc receiver.com 1234
Chat zwischen zwei Rechnern:
# Rechner A (Server)
nc -l 1234
# Rechner B (Client)
nc rechner-a.local 1234
# Jetzt kann man in beide Richtungen tippen
Banner-Grabbing:
# SSH-Version ermitteln
echo "" | nc -v -w 3 server.com 22
# SSH-2.0-OpenSSH_8.4
# SMTP-Banner
nc -v mail.example.com 25
# HTTP-Header
echo -e "HEAD / HTTP/1.0\r\n\r\n" | nc example.com 80
Proxy / Port-Weiterleitung:
# Einfacher Proxy (erfordert Schleife für mehrere Verbindungen)
nc -l 8080 | nc remote.com 80
Optionen:
| Option | Beschreibung |
|---|---|
-l | Listen-Modus (Server) |
-v | Verbose |
-z | Zero-I/O (nur Scan) |
-w SEC | Timeout |
-n | Kein DNS |
-u | UDP statt TCP |
-p PORT | Quell-Port |
-k | Keep-alive (mehrere Verbindungen) |
Debugging-Beispiele:
# Ist Dienst erreichbar?
nc -zv -w 3 db.example.com 5432 && echo "PostgreSQL OK" || echo "FEHLER"
# Alle gängigen Ports scannen
for port in 22 80 443 3306 5432 6379 27017; do
nc -zv -w 2 server.com $port 2>&1 | grep -q succeeded && echo "Port $port: OFFEN"
done
3 Dateiübertragung
3.1 wget – Dateien herunterladen
wget ist ein robustes Download-Tool mit Unterstützung für Wiederaufnahme und rekursive Downloads.
Installation:
brew install wget
Einfacher Download:
# Datei herunterladen
wget https://example.com/file.zip
# Mit anderem Namen speichern
wget -O myfile.zip https://example.com/file.zip
# In bestimmtes Verzeichnis
wget -P ~/Downloads https://example.com/file.zip
Abgebrochenen Download fortsetzen:
wget -c https://example.com/large-file.zip
Mehrere Dateien:
# Aus Liste
wget -i urls.txt
# Mehrere URLs
wget https://example.com/file1.zip https://example.com/file2.zip
Hintergrund-Download:
# Im Hintergrund mit Log
wget -b -o download.log https://example.com/file.zip
# Fortschritt prüfen
tail -f download.log
Geschwindigkeit begrenzen:
# Max 1 MB/s
wget --limit-rate=1m https://example.com/file.zip
# Max 500 KB/s
wget --limit-rate=500k https://example.com/file.zip
Webseite spiegeln:
# Komplette Website herunterladen
wget --mirror --convert-links --adjust-extension --page-requisites \
--no-parent https://example.com/
# Kurzform
wget -mkEpnp https://example.com/
Mit Authentifizierung:
# HTTP-Auth
wget --user=username --password=secret https://example.com/protected/file.zip
# Passwort interaktiv
wget --user=username --ask-password https://example.com/protected/file.zip
Cookies und Header:
# Mit Cookie
wget --header="Cookie: session=abc123" https://example.com/
# Custom User-Agent
wget --user-agent="Mozilla/5.0" https://example.com/
# Referer setzen
wget --referer="https://google.com" https://example.com/file.zip
Wichtige Optionen:
| Option | Beschreibung |
|---|---|
-O FILE | Ausgabedatei |
-P DIR | Ausgabeverzeichnis |
-c | Fortsetzen |
-b | Hintergrund |
-q | Quiet (keine Ausgabe) |
-v | Verbose |
--limit-rate | Geschwindigkeit begrenzen |
-r | Rekursiv |
-l DEPTH | Rekursionstiefe |
-np | No parent (nicht höher) |
-k | Links konvertieren |
-t N | Wiederholungsversuche |
--timeout=SEC | Timeout |
Alternative: curl
# curl ist auf macOS vorinstalliert
curl -O https://example.com/file.zip
# Mit Ausgabename
curl -o myfile.zip https://example.com/file.zip
# Fortsetzen
curl -C - -O https://example.com/file.zip
# Fortschrittsbalken
curl -# -O https://example.com/file.zip
3.2 scp – Sichere Kopie über SSH
scp kopiert Dateien verschlüsselt über SSH zwischen Rechnern.
Syntax:
scp [Optionen] QUELLE ZIEL
Datei hochladen:
# Lokale Datei auf Server
scp datei.txt user@server:/pfad/
# Mit Port
scp -P 2222 datei.txt user@server:/pfad/
# Mit SSH-Key
scp -i ~/.ssh/key datei.txt user@server:/pfad/
Datei herunterladen:
# Von Server auf lokal
scp user@server:/pfad/datei.txt ./
# Mit anderem Namen
scp user@server:/pfad/datei.txt lokaler-name.txt
Verzeichnis kopieren:
# Rekursiv (ganzes Verzeichnis)
scp -r ordner/ user@server:/pfad/
# Von Server
scp -r user@server:/pfad/ordner/ ./
Zwischen zwei Servern:
scp user1@server1:/pfad/datei.txt user2@server2:/pfad/
Mit SSH-Config:
# Wenn in ~/.ssh/config definiert:
# Host myserver
# HostName server.com
# User admin
scp datei.txt myserver:/pfad/
Optionen:
| Option | Beschreibung |
|---|---|
-r | Rekursiv (Verzeichnisse) |
-P PORT | SSH-Port |
-i KEY | Identity-File |
-p | Berechtigungen/Zeiten erhalten |
-C | Komprimierung |
-q | Quiet |
-v | Verbose |
-l LIMIT | Bandbreite begrenzen (Kbit/s) |
Fortschrittsanzeige:
# Standard: Fortschrittsbalken aktiv
scp large-file.zip user@server:/pfad/
# Ohne Fortschritt
scp -q large-file.zip user@server:/pfad/
Wildcards:
# Alle .txt-Dateien
scp *.txt user@server:/pfad/
# Alle Dateien eines Ordners auf Server
scp user@server:/pfad/*.log ./logs/
3.3 rsync – Erweiterte Synchronisation
Die Grundlagen von rsync werden in rsync – Effiziente Synchronisation und Spiegelung behandelt. Der Fokus dieses Abschnitts liegt auf der Netzwerkübertragung.
rsync über SSH (Standard):
# Auf Server kopieren
rsync -avz ~/projekt/ user@server:/backup/projekt/
# Von Server holen
rsync -avz user@server:/daten/ ~/lokale-kopie/
Mit SSH-Optionen:
# Anderer Port
rsync -avz -e "ssh -p 2222" ~/projekt/ user@server:/backup/
# Mit SSH-Key
rsync -avz -e "ssh -i ~/.ssh/mykey" ~/projekt/ user@server:/backup/
Bandbreite begrenzen:
# Max 1 MB/s
rsync -avz --bwlimit=1000 ~/projekt/ user@server:/backup/
Nur geänderte Dateien:
# Delta-Transfer (nur Unterschiede)
rsync -avz --checksum ~/projekt/ user@server:/backup/
Spiegel mit Löschen:
# Ziel exakt wie Quelle (ACHTUNG!)
rsync -avz --delete ~/projekt/ user@server:/backup/projekt/
# Erst Testlauf
rsync -avzn --delete ~/projekt/ user@server:/backup/projekt/
Bestimmte Dateien aus-/einschließen:
# Ausschließen
rsync -avz --exclude='*.log' --exclude='node_modules/' ~/projekt/ user@server:/backup/
# Aus Datei lesen
rsync -avz --exclude-from='exclude.txt' ~/projekt/ user@server:/backup/
# Nur bestimmte Dateien
rsync -avz --include='*.py' --exclude='*' ~/projekt/ user@server:/backup/
Fortschritt anzeigen:
# Fortschritt pro Datei
rsync -avz --progress ~/projekt/ user@server:/backup/
# Gesamtfortschritt
rsync -avz --info=progress2 ~/projekt/ user@server:/backup/
Backup-Skript:
#!/bin/zsh
# backup-to-server.sh
SRC="$HOME/Documents/"
DEST="user@backup-server:/backups/$(hostname)/"
LOG="$HOME/logs/backup-$(date +%Y%m%d).log"
rsync -avz --delete \
--exclude='.DS_Store' \
--exclude='*.tmp' \
--log-file="$LOG" \
"$SRC" "$DEST"
echo "Backup abgeschlossen: $(date)" >> "$LOG"
3.4 sftp – Interaktiver Dateitransfer
sftp bietet eine interaktive FTP-ähnliche Oberfläche über SSH.
Verbindung herstellen:
# Standard
sftp user@server
# Mit Port
sftp -P 2222 user@server
# Mit SSH-Key
sftp -i ~/.ssh/key user@server
# Direkt in Verzeichnis
sftp user@server:/pfad/
SFTP-Befehle:
| Befehl | Beschreibung |
|---|---|
ls / dir | Remote-Verzeichnis auflisten |
lls | Lokales Verzeichnis auflisten |
cd DIR | Remote-Verzeichnis wechseln |
lcd DIR | Lokales Verzeichnis wechseln |
pwd | Remote-Arbeitsverzeichnis |
lpwd | Lokales Arbeitsverzeichnis |
get FILE | Datei herunterladen |
put FILE | Datei hochladen |
mget PATTERN | Mehrere Dateien herunterladen |
mput PATTERN | Mehrere Dateien hochladen |
mkdir DIR | Verzeichnis erstellen |
rmdir DIR | Verzeichnis löschen |
rm FILE | Datei löschen |
rename OLD NEW | Umbenennen |
chmod MODE FILE | Berechtigungen ändern |
chown UID FILE | Besitzer ändern |
exit / quit | Beenden |
Typische Session:
sftp user@server
sftp> cd /var/www
sftp> ls
index.html styles.css app.js
sftp> get index.html
Fetching /var/www/index.html to index.html
sftp> lcd ~/Desktop
sftp> put new-styles.css styles.css
Uploading new-styles.css to /var/www/styles.css
sftp> exit
Mehrere Dateien:
sftp> mget *.log
sftp> mput *.html
Rekursiv (Verzeichnisse):
sftp> get -r remote-folder/
sftp> put -r local-folder/
Batch-Modus:
# Befehle aus Datei
sftp -b commands.txt user@server
# commands.txt:
# cd /var/www
# get index.html
# put styles.css
# exit
# Einzelner Befehl
echo "get /var/log/app.log" | sftp user@server
Mit SSH-Config:
# Wenn Host in ~/.ssh/config definiert
sftp myserver
Vergleich der Übertragungstools:
| Merkmal | scp | rsync | sftp |
|---|---|---|---|
| Interaktiv | ❌ | ❌ | ✅ |
| Delta-Transfer | ❌ | ✅ | ❌ |
| Fortsetzen | ❌ | ✅ | ❌ |
| Batch-fähig | ✅ | ✅ | ✅ |
| Verzeichnisse | -r | ✅ | -r |
| Bandbreiten-Limit | ✅ | ✅ | ❌ |
| Löschen am Ziel | ❌ | ✅ | ❌ |
| Anwendungsfall | Schnelle Kopie | Backup/Sync | Browsing |
Empfehlung:
- scp: Einzelne Dateien schnell kopieren
- rsync: Backups, Synchronisation, große Datenmengen
- sftp: Interaktives Arbeiten, Dateien browsen
Datenformate & Streams
Dieses Kapitel behandelt Tools zur Verarbeitung strukturierter Datenformate (JSON, YAML, CSV) sowie Komprimierung und Archivierung.
1 JSON
JSON (JavaScript Object Notation) ist das Standard-Format für APIs und Konfigurationsdateien. jq ist das mächtigste Tool zur JSON-Verarbeitung auf der Kommandozeile.
1.1 jq – Installation und Grundlagen
Installation:
brew install jq
# Version prüfen
jq --version
Grundlegende Nutzung:
# JSON formatieren (Pretty Print)
echo '{"name":"Max","age":30}' | jq .
# Aus Datei lesen
jq . data.json
# Kompakt ausgeben
jq -c . data.json
Beispiel-JSON für diese Referenz:
{
"users": [
{"id": 1, "name": "Alice", "email": "alice@example.com", "active": true},
{"id": 2, "name": "Bob", "email": "bob@example.com", "active": false},
{"id": 3, "name": "Carol", "email": "carol@example.com", "active": true}
],
"meta": {
"total": 3,
"page": 1
}
}
Grundlegende Filter:
# Ganzes Dokument
jq '.' data.json
# Einzelnes Feld
jq '.meta' data.json
# {"total": 3, "page": 1}
# Verschachteltes Feld
jq '.meta.total' data.json
# 3
# Array
jq '.users' data.json
# Erstes Array-Element
jq '.users[0]' data.json
# Letztes Element
jq '.users[-1]' data.json
# Bereich (Slice)
jq '.users[0:2]' data.json
1.2 Filter und Selektoren
Feld-Zugriff:
# Punkt-Notation
jq '.users[0].name' data.json
# "Alice"
# Ohne Quotes
jq -r '.users[0].name' data.json
# Alice
# Mehrere Felder
jq '.users[0] | .name, .email' data.json
# "Alice"
# "alice@example.com"
Array-Operationen:
# Alle Elemente iterieren
jq '.users[]' data.json
# Bestimmtes Feld aller Elemente
jq '.users[].name' data.json
# "Alice"
# "Bob"
# "Carol"
# Als Array sammeln
jq '[.users[].name]' data.json
# ["Alice", "Bob", "Carol"]
# Array-Länge
jq '.users | length' data.json
# 3
Filtern mit select:
# Nach Bedingung filtern
jq '.users[] | select(.active == true)' data.json
# Nach Wert filtern
jq '.users[] | select(.id > 1)' data.json
# String-Matching
jq '.users[] | select(.name | contains("o"))' data.json
# Regex
jq '.users[] | select(.email | test("@example"))' data.json
# Mehrere Bedingungen (AND)
jq '.users[] | select(.active == true and .id > 1)' data.json
# OR-Bedingung
jq '.users[] | select(.active == true or .id == 2)' data.json
Map und Filter:
# Map über Array
jq '.users | map(.name)' data.json
# ["Alice", "Bob", "Carol"]
# Map mit Transformation
jq '.users | map(.name | ascii_upcase)' data.json
# ["ALICE", "BOB", "CAROL"]
# Filter (select als map)
jq '.users | map(select(.active))' data.json
# Kombiniert
jq '.users | map(select(.active)) | map(.email)' data.json
# ["alice@example.com", "carol@example.com"]
Nützliche Operatoren:
| Operator | Beschreibung | Beispiel |
|---|---|---|
. | Identität (ganzes Objekt) | jq '.' |
.field | Feld-Zugriff | jq '.name' |
.[] | Array-Iterator | jq '.users[]' |
.[n] | Index-Zugriff | jq '.[0]' |
| | | Pipe (verketten) | jq ‘.users[] | .name’ |
, | Mehrere Ausgaben | jq '.name, .age' |
? | Optional (kein Fehler) | jq '.missing?' |
// | Default-Wert | jq '.missing // "N/A"' |
1.3 Transformation und Ausgabeformatierung
Objekte konstruieren:
# Neues Objekt erstellen
jq '.users[] | {username: .name, mail: .email}' data.json
# Mit statischen Feldern
jq '.users[] | {type: "user", name: .name}' data.json
# Alle in Array
jq '[.users[] | {username: .name, mail: .email}]' data.json
Werte modifizieren:
# Feld ändern
jq '.meta.page = 2' data.json
# Feld hinzufügen
jq '.meta.timestamp = "2024-01-15"' data.json
# Feld löschen
jq 'del(.meta.page)' data.json
# In Array-Elementen ändern
jq '.users[0].name = "Alicia"' data.json
# Alle Array-Elemente ändern
jq '.users[].active = true' data.json
Ausgabeformatierung:
# Raw-Strings (ohne Quotes)
jq -r '.users[].name' data.json
# Kompakt (eine Zeile)
jq -c '.' data.json
# Tab-Einrückung
jq --tab '.' data.json
# Sortierte Keys
jq -S '.' data.json
# Als TSV (Tab-getrennt)
jq -r '.users[] | [.id, .name, .email] | @tsv' data.json
# 1 Alice alice@example.com
# 2 Bob bob@example.com
# Als CSV
jq -r '.users[] | [.id, .name, .email] | @csv' data.json
# 1,"Alice","alice@example.com"
# URI-Encoding
jq -r '.users[0].email | @uri' data.json
# Base64
jq -r '.users[0].name | @base64' data.json
String-Interpolation:
# Template-String
jq -r '.users[] | "User: \(.name) <\(.email)>"' data.json
# User: Alice <alice@example.com>
# User: Bob <bob@example.com>
# User: Carol <carol@example.com>
Eingebaute Funktionen:
| Funktion | Beschreibung | Beispiel |
|---|---|---|
length | Länge | .users | length |
keys | Objekt-Keys | .meta | keys |
values | Objekt-Werte | .meta | values |
type | Typ ermitteln | .users | type |
sort | Array sortieren | .users | sort_by(.name) |
unique | Duplikate entfernen | [.users[].active] | unique |
reverse | Array umkehren | .users | reverse |
first / last | Erstes/Letztes | .users | first |
add | Summe/Konkatenation | [.users[].id] | add |
min / max | Minimum/Maximum | [.users[].id] | max |
group_by | Gruppieren | .users | group_by(.active) |
ascii_downcase | Kleinbuchstaben | .name | ascii_downcase |
split | String teilen | .email | split("@") |
join | Array verbinden | [.users[].name] | join(", ") |
contains | Enthält | .name | contains("li") |
startswith | Beginnt mit | .email | startswith("a") |
sub / gsub | Ersetzen | .name | gsub("a"; "X") |
1.4 Praxisbeispiele (API-Responses verarbeiten)
curl mit jq:
# API-Response formatieren
curl -s https://api.github.com/users/octocat | jq .
# Bestimmte Felder extrahieren
curl -s https://api.github.com/users/octocat | jq '{name, bio, location}'
# Array-Response verarbeiten
curl -s https://api.github.com/users/octocat/repos | jq '.[].name'
# Top 5 nach Stars
curl -s https://api.github.com/users/octocat/repos | \
jq 'sort_by(.stargazers_count) | reverse | .[0:5] | .[].name'
JSON-Konfiguration bearbeiten:
# package.json Version auslesen
jq -r '.version' package.json
# Version erhöhen
jq '.version = "2.0.0"' package.json > package.json.tmp && mv package.json.tmp package.json
# Dependency hinzufügen
jq '.dependencies.lodash = "^4.17.21"' package.json
# Script hinzufügen
jq '.scripts.test = "jest"' package.json
Log-Dateien analysieren:
# JSON-Logs filtern (ein JSON pro Zeile)
cat app.log | jq 'select(.level == "error")'
# Fehler zählen
cat app.log | jq -s 'map(select(.level == "error")) | length'
# Nach Zeitraum filtern
cat app.log | jq 'select(.timestamp > "2024-01-15T00:00:00")'
# Gruppieren nach Level
cat app.log | jq -s 'group_by(.level) | map({level: .[0].level, count: length})'
Mehrere JSON-Dateien:
# Alle JSON-Dateien zusammenführen
jq -s '.' *.json
# In ein Array
jq -s 'add' file1.json file2.json
# Felder aus mehreren Dateien
jq -s 'map(.name)' *.json
Mit Variablen arbeiten:
# Variable übergeben
jq --arg name "Alice" '.users[] | select(.name == $name)' data.json
# Numerische Variable
jq --argjson id 2 '.users[] | select(.id == $id)' data.json
# Aus Umgebungsvariable
export USER_ID=1
jq --argjson id "$USER_ID" '.users[] | select(.id == $id)' data.json
Slurp-Modus (mehrere Objekte als Array):
# Mehrere JSON-Zeilen als Array
echo -e '{"a":1}\n{"a":2}\n{"a":3}' | jq -s '.'
# [{"a":1},{"a":2},{"a":3}]
# Summe berechnen
echo -e '{"a":1}\n{"a":2}\n{"a":3}' | jq -s 'map(.a) | add'
# 6
2 YAML
YAML ist ein menschenlesbares Format, beliebt für Konfigurationsdateien (Docker, Kubernetes, CI/CD).
2.1 yq – Installation und Grundlagen
Es gibt zwei verschiedene yq-Tools. Wir verwenden hier Mike Farah’s Version (Go-basiert):
Installation:
brew install yq
# Version prüfen
yq --version
# yq (https://github.com/mikefarah/yq/) version v4.x
note
Es gibt auch ein Python-basiertes yq (pip install yq), das jq als Backend nutzt. Die Syntax unterscheidet sich leicht.
Beispiel-YAML:
# config.yaml
server:
host: localhost
port: 8080
ssl: true
database:
host: db.example.com
port: 5432
name: myapp
users:
- name: Alice
role: admin
- name: Bob
role: user
Grundlegende Nutzung:
# YAML formatiert ausgeben
yq '.' config.yaml
# Einzelnes Feld
yq '.server.host' config.yaml
# localhost
# Verschachtelt
yq '.database.port' config.yaml
# 5432
2.2 YAML lesen und bearbeiten
Felder auslesen:
# Einfaches Feld
yq '.server.port' config.yaml
# Array-Element
yq '.users[0].name' config.yaml
# Alice
# Alle Array-Elemente
yq '.users[].name' config.yaml
# Alice
# Bob
# Mit Länge
yq '.users | length' config.yaml
# 2
Werte ändern:
# Feld ändern (in-place)
yq -i '.server.port = 9090' config.yaml
# Ohne in-place (stdout)
yq '.server.port = 9090' config.yaml
# Neues Feld hinzufügen
yq -i '.server.timeout = 30' config.yaml
# Verschachteltes Feld hinzufügen
yq -i '.logging.level = "debug"' config.yaml
# Feld löschen
yq -i 'del(.server.ssl)' config.yaml
Array-Operationen:
# Element hinzufügen
yq -i '.users += [{"name": "Carol", "role": "user"}]' config.yaml
# Element am Anfang
yq -i '.users = [{"name": "Admin", "role": "admin"}] + .users' config.yaml
# Element löschen
yq -i 'del(.users[1])' config.yaml
# Filtern
yq '.users[] | select(.role == "admin")' config.yaml
Umgebungsvariablen einsetzen:
# Variable einsetzen
yq -i '.database.host = env(DB_HOST)' config.yaml
# Mit Default
yq '.database.host // "localhost"' config.yaml
# Aus Umgebung lesen
export DB_HOST="production.db.com"
yq -i '.database.host = env(DB_HOST)' config.yaml
Kommentare und Formatierung:
# Kommentare erhalten
yq '.' config.yaml
# Kommentar hinzufügen
yq -i '.server.port line_comment="HTTP Port"' config.yaml
# Ausgabe-Stil
yq -o=json '.' config.yaml # Als JSON
yq -o=props '.' config.yaml # Als Properties
yq -o=xml '.' config.yaml # Als XML
2.3 Konvertierung JSON ↔ YAML
YAML zu JSON:
# Standard-Konvertierung
yq -o=json '.' config.yaml
# Kompakt
yq -o=json -I=0 '.' config.yaml
# In Datei speichern
yq -o=json '.' config.yaml > config.json
JSON zu YAML:
# JSON einlesen und als YAML ausgeben
yq -P '.' data.json
# Von stdin
echo '{"name": "test", "value": 123}' | yq -P '.'
# name: test
# value: 123
# In Datei
yq -P '.' data.json > data.yaml
Mehrere Dokumente:
# YAML mit mehreren Dokumenten (---)
yq eval-all '.' multi-doc.yaml
# Dokumente zählen
yq eval-all 'documentIndex' multi-doc.yaml | wc -l
# Bestimmtes Dokument
yq 'select(documentIndex == 0)' multi-doc.yaml
Praktische Beispiele:
# Docker-Compose Port ändern
yq -i '.services.web.ports[0] = "9090:80"' docker-compose.yaml
# Kubernetes Replicas erhöhen
yq -i '.spec.replicas = 5' deployment.yaml
# GitHub Actions Workflow bearbeiten
yq -i '.jobs.build.runs-on = "ubuntu-22.04"' .github/workflows/ci.yaml
# Alle Image-Tags auslesen
yq '.spec.template.spec.containers[].image' deployment.yaml
3 CSV
CSV (Comma-Separated Values) ist das universelle Tabellenformat. csvkit bietet eine Suite von Tools zur CSV-Verarbeitung.
3.1 csvkit – Installation und Überblick
Installation:
pip install csvkit --break-system-packages
# oder
brew install csvkit
csvkit-Tools:
| Tool | Beschreibung |
|---|---|
csvlook | Formatierte Tabellenansicht |
csvcut | Spalten auswählen |
csvgrep | Zeilen filtern |
csvstat | Statistiken |
csvsort | Sortieren |
csvjoin | Tabellen verbinden |
csvstack | Tabellen stapeln |
csvformat | Format konvertieren |
in2csv | Zu CSV konvertieren |
sql2csv | SQL-Abfrage zu CSV |
csvsql | SQL auf CSV ausführen |
Beispiel-CSV:
id,name,department,salary,start_date
1,Alice,Engineering,75000,2020-03-15
2,Bob,Marketing,65000,2019-07-22
3,Carol,Engineering,80000,2018-11-01
4,David,Sales,70000,2021-01-10
5,Eve,Marketing,72000,2020-09-05
3.2 csvlook, csvcut, csvgrep
csvlook – Formatierte Anzeige:
# Tabelle anzeigen
csvlook employees.csv
# | id | name | department | salary | start_date |
# | -- | ----- | ----------- | ------ | ---------- |
# | 1 | Alice | Engineering | 75000 | 2020-03-15 |
# | 2 | Bob | Marketing | 65000 | 2019-07-22 |
# ...
# Erste 3 Zeilen
head -4 employees.csv | csvlook
# Spaltenbreite begrenzen
csvlook --max-column-width 15 employees.csv
# Ohne Header-Trennlinie
csvlook --no-header-row employees.csv
csvcut – Spalten auswählen:
# Spaltennamen anzeigen
csvcut -n employees.csv
# 1: id
# 2: name
# 3: department
# 4: salary
# 5: start_date
# Spalten nach Nummer
csvcut -c 1,2,4 employees.csv
# Spalten nach Name
csvcut -c name,salary employees.csv
# Spalten ausschließen
csvcut -C id,start_date employees.csv
# Reihenfolge ändern
csvcut -c salary,name,department employees.csv
csvgrep – Zeilen filtern:
# Nach Wert filtern
csvgrep -c department -m "Engineering" employees.csv
# Regex-Suche
csvgrep -c name -r "^[A-C]" employees.csv
# Invertieren (NOT)
csvgrep -c department -m "Marketing" -i employees.csv
# Mehrere Bedingungen (Pipe)
csvgrep -c department -m "Engineering" employees.csv | csvgrep -c salary -r "^[78]"
Kombinationen:
# Engineering-Mitarbeiter, nur Name und Gehalt
csvgrep -c department -m "Engineering" employees.csv | csvcut -c name,salary | csvlook
# Ausgabe:
# | name | salary |
# | ----- | ------ |
# | Alice | 75000 |
# | Carol | 80000 |
3.3 csvstat, csvsort, csvjoin
csvstat – Statistiken:
# Vollständige Statistiken
csvstat employees.csv
# Nur bestimmte Spalte
csvstat -c salary employees.csv
# Type of data: Number
# Contains null values: False
# Unique values: 5
# Smallest value: 65000
# Largest value: 80000
# Sum: 362000
# Mean: 72400
# Median: 72000
# ...
# Nur bestimmte Statistik
csvstat --mean -c salary employees.csv
csvstat --sum -c salary employees.csv
csvstat --count employees.csv
csvsort – Sortieren:
# Nach Spalte sortieren
csvsort -c salary employees.csv
# Absteigend
csvsort -c salary -r employees.csv
# Nach mehreren Spalten
csvsort -c department,salary employees.csv
# Numerisch sortieren (automatisch erkannt)
csvsort -c start_date employees.csv
csvjoin – Tabellen verbinden:
# Beispiel: departments.csv
# id,department_name,budget
# 1,Engineering,500000
# 2,Marketing,300000
# 3,Sales,400000
# employees_dept.csv (mit department_id statt name)
# id,name,department_id,salary
# 1,Alice,1,75000
# 2,Bob,2,65000
# Inner Join
csvjoin -c department_id,id employees_dept.csv departments.csv
# Left Join
csvjoin --left -c department_id,id employees_dept.csv departments.csv
# Ausgabespalten wählen
csvjoin -c department_id,id employees_dept.csv departments.csv | csvcut -c name,department_name,salary
csvstack – Tabellen stapeln:
# Zwei CSVs untereinander
csvstack file1.csv file2.csv
# Mit Quell-Kennzeichnung
csvstack -g "Q1,Q2" -n quarter file1.csv file2.csv
csvsql – SQL auf CSV:
# SQL-Abfrage
csvsql --query "SELECT name, salary FROM employees WHERE salary > 70000" employees.csv
# Aggregation
csvsql --query "SELECT department, AVG(salary) as avg_salary FROM employees GROUP BY department" employees.csv
# Join mit SQL
csvsql --query "SELECT e.name, d.department_name
FROM employees e
JOIN departments d ON e.department_id = d.id" \
employees.csv departments.csv
3.4 Alternativen: mlr (Miller), xsv
Miller (mlr) – Mächtiges Datenverarbeitungs-Tool:
# Installation
brew install miller
# CSV lesen
mlr --csv cat employees.csv
# Pretty Print
mlr --icsv --opprint cat employees.csv
# Filtern
mlr --csv filter '$salary > 70000' employees.csv
# Spalten auswählen
mlr --csv cut -f name,salary employees.csv
# Transformieren
mlr --csv put '$bonus = $salary * 0.1' employees.csv
# Gruppieren
mlr --csv stats1 -a mean -f salary -g department employees.csv
# Sortieren
mlr --csv sort -nr salary employees.csv
# JSON-Ausgabe
mlr --icsv --ojson cat employees.csv
Miller Vorteile:
- Sehr schnell (C-basiert)
- Unterstützt CSV, JSON, DKVP, Markdown
- Mächtige DSL für Transformationen
- Streaming-fähig
xsv – Extrem schnelles CSV-Tool:
# Installation
brew install xsv
# Statistiken (sehr schnell)
xsv stats employees.csv | xsv table
# Spalten
xsv select name,salary employees.csv
# Suchen (schneller als csvgrep)
xsv search -s department "Engineering" employees.csv
# Zählen
xsv count employees.csv
# Häufigkeiten
xsv frequency -s department employees.csv
# Sampling
xsv sample 100 large-file.csv
# Sortieren
xsv sort -s salary -R employees.csv
# Index erstellen (für sehr große Dateien)
xsv index employees.csv
xsv slice -i 1000 employees.csv
xsv Vorteile:
- Extrem schnell (Rust-basiert)
- Ideal für große Dateien
- Index-Unterstützung
Vergleich:
| Feature | csvkit | Miller | xsv |
|---|---|---|---|
| Geschwindigkeit | Mittel | Schnell | Sehr schnell |
| SQL-Support | ✅ | ❌ | ❌ |
| JSON-Support | ⚠️ | ✅ | ❌ |
| Transformation | Basis | Sehr gut | Basis |
| Große Dateien | ⚠️ | ✅ | ✅ |
| Verfügbarkeit | pip/brew | brew | brew |
4 Komprimierung & Archivierung
4.1 tar – Archive erstellen und entpacken
tar (Tape Archive) kombiniert mehrere Dateien in ein Archiv. Ursprünglich ohne Kompression, heute meist mit gzip oder xz kombiniert.
Archiv erstellen:
# Ohne Kompression
tar -cvf archiv.tar ordner/
# c = create
# v = verbose
# f = file
# Mit gzip-Kompression
tar -czvf archiv.tar.gz ordner/
# z = gzip
# Mit bzip2-Kompression
tar -cjvf archiv.tar.bz2 ordner/
# j = bzip2
# Mit xz-Kompression (beste Kompression)
tar -cJvf archiv.tar.xz ordner/
# J = xz
# Mehrere Dateien/Ordner
tar -czvf archiv.tar.gz datei1.txt datei2.txt ordner/
# Mit Ausschlüssen
tar -czvf archiv.tar.gz --exclude='*.log' --exclude='node_modules' ordner/
# Aus Liste
tar -czvf archiv.tar.gz -T files.txt
Archiv entpacken:
# tar
tar -xvf archiv.tar
# tar.gz / tgz
tar -xzvf archiv.tar.gz
# tar.bz2
tar -xjvf archiv.tar.bz2
# tar.xz
tar -xJvf archiv.tar.xz
# In bestimmtes Verzeichnis
tar -xzvf archiv.tar.gz -C /ziel/verzeichnis/
# Nur bestimmte Dateien
tar -xzvf archiv.tar.gz pfad/zur/datei.txt
Archiv-Inhalt anzeigen:
# Inhalt auflisten
tar -tvf archiv.tar.gz
# Nur Dateinamen
tar -tf archiv.tar.gz
# Mit grep filtern
tar -tf archiv.tar.gz | grep "\.py$"
Wichtige Optionen:
| Option | Beschreibung |
|---|---|
-c | Create (erstellen) |
-x | Extract (entpacken) |
-t | List (auflisten) |
-v | Verbose |
-f FILE | Archivdatei |
-z | gzip |
-j | bzip2 |
-J | xz |
-C DIR | Zielverzeichnis |
--exclude | Ausschließen |
-p | Berechtigungen erhalten |
--strip-components=N | N Pfad-Ebenen entfernen |
Praktische Beispiele:
# Backup mit Datum
tar -czvf "backup-$(date +%Y%m%d).tar.gz" ~/Documents/
# Nur neue/geänderte Dateien (inkrementell)
tar -czvf backup.tar.gz --newer-mtime="2024-01-01" ~/Documents/
# Über SSH auf Remote-Server
tar -czvf - ordner/ | ssh user@server "cat > backup.tar.gz"
# Von Remote-Server entpacken
ssh user@server "cat backup.tar.gz" | tar -xzvf -
# Pfad-Präfix entfernen beim Entpacken
tar -xzvf archiv.tar.gz --strip-components=1
4.2 gzip / gunzip – Einzeldateien komprimieren
gzip komprimiert einzelne Dateien (ersetzt Original durch .gz-Datei).
Komprimieren:
# Datei komprimieren (Original wird ersetzt)
gzip datei.txt
# Ergebnis: datei.txt.gz
# Original behalten
gzip -k datei.txt
# Kompressionsgrad (1-9, 9=beste)
gzip -9 datei.txt
# Schnellste Kompression
gzip -1 datei.txt
# Mehrere Dateien
gzip file1.txt file2.txt file3.txt
# Rekursiv (alle Dateien in Ordner)
gzip -r ordner/
Dekomprimieren:
# Entpacken
gunzip datei.txt.gz
# oder
gzip -d datei.txt.gz
# Original behalten
gunzip -k datei.txt.gz
# Nach stdout (Original behalten)
gunzip -c datei.txt.gz > datei.txt
zcat datei.txt.gz > datei.txt
Informationen:
# Kompressionsinfos
gzip -l datei.txt.gz
# compressed uncompressed ratio uncompressed_name
# 1234 5678 78.3% datei.txt
# Integrität prüfen
gzip -t datei.txt.gz
Mit Pipes:
# Komprimiert speichern
cat large-file.log | gzip > large-file.log.gz
# Komprimierte Datei durchsuchen
zgrep "error" logfile.gz
zcat logfile.gz | grep "error"
# Komprimierte Datei anzeigen
zless logfile.gz
zcat logfile.gz | less
4.3 zip / unzip – ZIP-Archive
ZIP ist das universelle Archivformat, kompatibel mit Windows und macOS Finder.
Archiv erstellen:
# Dateien zippen
zip archiv.zip file1.txt file2.txt
# Ordner (rekursiv)
zip -r archiv.zip ordner/
# Mit Passwort
zip -e -r archiv.zip ordner/
# Kompressionsgrad (0-9)
zip -9 -r archiv.zip ordner/
# Keine Kompression (nur archivieren)
zip -0 -r archiv.zip ordner/
# Ausschließen
zip -r archiv.zip ordner/ -x "*.log" -x "*.tmp"
# Versteckte Dateien ausschließen
zip -r archiv.zip ordner/ -x ".*" -x "*/.*"
Archiv entpacken:
# Entpacken
unzip archiv.zip
# In bestimmtes Verzeichnis
unzip archiv.zip -d /ziel/
# Nur bestimmte Dateien
unzip archiv.zip "*.txt"
# Überschreiben ohne Nachfrage
unzip -o archiv.zip
# Nie überschreiben
unzip -n archiv.zip
# Leise
unzip -q archiv.zip
Archiv verwalten:
# Inhalt anzeigen
unzip -l archiv.zip
# Detailliert
unzip -v archiv.zip
# Integrität prüfen
unzip -t archiv.zip
# Datei zum Archiv hinzufügen
zip archiv.zip neue-datei.txt
# Datei aktualisieren (nur wenn neuer)
zip -u archiv.zip datei.txt
# Datei aus Archiv löschen
zip -d archiv.zip datei.txt
Passwortgeschützte Archive:
# Mit Passwort erstellen
zip -e -r geheim.zip ordner/
# Entpacken (Passwort-Prompt)
unzip geheim.zip
# Passwort auf Kommandozeile (unsicher!)
unzip -P "geheim123" geheim.zip
4.4 xz – Hohe Kompression
xz bietet die beste Kompressionsrate, ist aber langsamer als gzip.
Komprimieren:
# Standard-Kompression
xz datei.txt
# Ergebnis: datei.txt.xz
# Original behalten
xz -k datei.txt
# Maximale Kompression (langsam)
xz -9 datei.txt
# Schnelle Kompression
xz -1 datei.txt
# Extreme Kompression
xz -e -9 datei.txt
# Mit Threads (schneller)
xz -T 0 datei.txt # alle CPUs
xz -T 4 datei.txt # 4 Threads
Dekomprimieren:
# Entpacken
unxz datei.txt.xz
# oder
xz -d datei.txt.xz
# Original behalten
unxz -k datei.txt.xz
# Nach stdout
xzcat datei.txt.xz
Informationen:
# Details anzeigen
xz -l datei.txt.xz
# Integrität prüfen
xz -t datei.txt.xz
4.5 bzip2 – Alternative Kompression
bzip2 bietet bessere Kompression als gzip, ist aber langsamer.
Komprimieren:
# Komprimieren
bzip2 datei.txt
# Ergebnis: datei.txt.bz2
# Original behalten
bzip2 -k datei.txt
# Kompressionsgrad
bzip2 -9 datei.txt
Dekomprimieren:
# Entpacken
bunzip2 datei.txt.bz2
# oder
bzip2 -d datei.txt.bz2
# Nach stdout
bzcat datei.txt.bz2
4.6 Kombinationen (tar.gz, tar.xz)
Vergleich der Formate:
| Format | Kompression | Geschwindigkeit | Verbreitung |
|---|---|---|---|
.tar | Keine | Sehr schnell | Unix |
.tar.gz / .tgz | Gut | Schnell | Universell |
.tar.bz2 | Besser | Mittel | Unix |
.tar.xz | Beste | Langsam | Modern |
.zip | Gut | Schnell | Universell |
Empfehlungen:
# Für schnelle Backups
tar -czvf backup.tar.gz ordner/
# Für maximale Kompression (Archive, Downloads)
tar -cJvf archiv.tar.xz ordner/
# Für Windows-Kompatibilität
zip -r archiv.zip ordner/
# Für sehr große Dateien (mit Fortschritt)
tar -cvf - ordner/ | pv | gzip > archiv.tar.gz
Cheatsheet:
# tar erstellen
tar -czvf archiv.tar.gz ordner/ # gzip
tar -cjvf archiv.tar.bz2 ordner/ # bzip2
tar -cJvf archiv.tar.xz ordner/ # xz
# tar entpacken
tar -xzvf archiv.tar.gz # gzip
tar -xjvf archiv.tar.bz2 # bzip2
tar -xJvf archiv.tar.xz # xz
# tar auflisten
tar -tzvf archiv.tar.gz
# Einzeldateien
gzip/gunzip datei.txt # .gz
bzip2/bunzip2 datei.txt # .bz2
xz/unxz datei.txt # .xz
# ZIP
zip -r archiv.zip ordner/
unzip archiv.zip
# Komprimierte Dateien lesen
zcat/zless/zgrep # .gz
bzcat/bzless/bzgrep # .bz2
xzcat/xzless/xzgrep # .xz
Prozesse & Signale
Dieses Kapitel behandelt erweiterte Tools zur Prozessüberwachung, das Signal-System zur Prozesskommunikation und die Verwaltung von Prozessgruppen und Jobs.
1 Erweiterte Monitoring-Tools
Neben den Standard-Tools ps, top und htop bietet macOS spezialisierte Werkzeuge für detailliertes System-Monitoring.
1.1 iotop – I/O-Überwachung
macOS hat kein natives iotop wie Linux, aber es gibt Alternativen:
Alternative 1: sudo iotop (falls installiert)
# Installation (falls verfügbar)
brew install iotop
# Ausführen (benötigt root)
sudo iotop
Alternative 2: fs_usage für I/O-Überwachung
# Disk-I/O aller Prozesse
sudo fs_usage -f diskio
# Bestimmter Prozess
sudo fs_usage -f diskio -w | grep Safari
Alternative 3: iostat – Disk-Statistiken
# Disk-I/O Statistiken
iostat
# Alle 2 Sekunden aktualisieren
iostat -w 2
# Detailliert mit Disk-Namen
iostat -d
# Bestimmtes Intervall, 5 Messungen
iostat 2 5
Ausgabe verstehen:
disk0 cpu load average
KB/t tps MB/s us sy id 1m 5m 15m
24.00 45 1.06 5 3 92 1.23 1.45 1.67
| Spalte | Beschreibung |
|---|---|
| KB/t | Kilobytes pro Transfer |
| tps | Transfers pro Sekunde |
| MB/s | Megabytes pro Sekunde |
| us/sy/id | CPU: User/System/Idle % |
Alternative 4: Activity Monitor CLI-Daten
# Top-Prozesse nach Disk-Nutzung
top -o disk -l 1 -n 10 | tail -n +13
1.2 vm_stat – Speicherstatistiken
vm_stat zeigt detaillierte Statistiken des virtuellen Speichersystems.
Grundlegende Nutzung:
# Einmalige Ausgabe
vm_stat
# Ausgabe:
# Mach Virtual Memory Statistics: (page size of 16384 bytes)
# Pages free: 12345.
# Pages active: 67890.
# Pages inactive: 11111.
# Pages speculative: 2222.
# Pages throttled: 0.
# Pages wired down: 33333.
# Pages purgeable: 4444.
# ...
Kontinuierliche Überwachung:
# Alle 1 Sekunde
vm_stat 1
# Alle 5 Sekunden
vm_stat 5
Ausgabe verstehen:
| Metrik | Beschreibung |
|---|---|
| Pages free | Freie Speicherseiten |
| Pages active | Aktiv genutzter Speicher |
| Pages inactive | Kürzlich ungenutzt, noch im RAM |
| Pages speculative | Spekulativ geladene Daten |
| Pages wired down | Vom Kernel gesperrt (nicht auslagerbar) |
| Pages purgeable | Kann bei Bedarf freigegeben werden |
| Pageins | Von Disk in RAM geladen |
| Pageouts | Von RAM auf Disk ausgelagert |
| Swapins/Swapouts | Swap-Aktivität |
In lesbare Werte umrechnen:
# Page-Größe ermitteln
pagesize=$(vm_stat | head -1 | grep -oE '[0-9]+')
# Freier Speicher in MB
free_pages=$(vm_stat | grep "Pages free" | awk '{print $3}' | tr -d '.')
echo "Frei: $(( free_pages * pagesize / 1024 / 1024 )) MB"
Skript für lesbare Ausgabe:
#!/bin/zsh
# mem-usage.sh
pagesize=$(pagesize)
get_pages() {
vm_stat | grep "$1" | awk '{print $NF}' | tr -d '.'
}
free=$(($(get_pages "Pages free") * pagesize / 1024 / 1024))
active=$(($(get_pages "Pages active") * pagesize / 1024 / 1024))
inactive=$(($(get_pages "Pages inactive") * pagesize / 1024 / 1024))
wired=$(($(get_pages "Pages wired") * pagesize / 1024 / 1024))
echo "Speicher-Nutzung:"
echo " Frei: ${free} MB"
echo " Aktiv: ${active} MB"
echo " Inaktiv: ${inactive} MB"
echo " Wired: ${wired} MB"
1.3 fs_usage – Dateisystem-Aktivität
fs_usage zeigt Dateisystem-Aktivität in Echtzeit – ideal zum Debuggen von I/O-Problemen.
Grundlegende Nutzung:
# Alle Dateisystem-Aktivität (benötigt root)
sudo fs_usage
# Nur Disk-I/O
sudo fs_usage -f diskio
# Nur Netzwerk
sudo fs_usage -f network
# Nur Dateisystem-Calls
sudo fs_usage -f filesys
Nach Prozess filtern:
# Bestimmter Prozess (Name)
sudo fs_usage -w Safari
# Bestimmte PID
sudo fs_usage -w -p 1234
# Mehrere Prozesse
sudo fs_usage -w Safari Chrome Firefox
# Prozess ausschließen
sudo fs_usage -e Safari
Ausgabe-Optionen:
# Breite Ausgabe (vollständige Pfade)
sudo fs_usage -w
# Mit Timestamps
sudo fs_usage -t
# Kombiniert
sudo fs_usage -w -f diskio -t
Ausgabe verstehen:
14:23:45 RdData D=0x012345 B=0x1000 /path/to/file Safari
14:23:45 open F=3 /path/to/file Safari
14:23:45 read F=3 B=0x400 Safari
14:23:45 close F=3 Safari
| Spalte | Beschreibung |
|---|---|
| Timestamp | Zeitstempel |
| Operation | read, write, open, close, stat, etc. |
| F= | File Descriptor |
| B= | Bytes |
| D= | Disk Block |
| Pfad | Betroffene Datei |
| Prozess | Prozessname |
Praktische Anwendungen:
# Was liest/schreibt ein Prozess?
sudo fs_usage -w -f diskio Spotlight
# Welche Dateien öffnet eine App beim Start?
sudo fs_usage -w -f filesys Safari 2>&1 | grep open
# Netzwerkaktivität eines Prozesses
sudo fs_usage -w -f network curl
# In Datei protokollieren
sudo fs_usage -w Safari > fs_log.txt 2>&1 &
# Später: kill %1
1.4 nettop – Netzwerk pro Prozess
nettop zeigt Netzwerkverbindungen und Bandbreite pro Prozess – wie top für Netzwerk.
Grundlegende Nutzung:
# Interaktive Ansicht
nettop
# Nicht-interaktiv (einmalig)
nettop -l 1
# Alle 2 Sekunden, 5 Messungen
nettop -l 5 -s 2
Filter-Optionen:
# Nur TCP
nettop -t tcp
# Nur UDP
nettop -t udp
# Bestimmter Prozess
nettop -p Safari
# Nur mit Traffic (Delta-Modus)
nettop -d
Ausgabe-Optionen:
# Nur bestimmte Spalten
nettop -c all # Alle Spalten
nettop -c bytes_in,bytes_out
# Sortieren
nettop -o bytes_in # Nach eingehenden Bytes
# JSON-Ausgabe
nettop -j -l 1
Interaktive Tastenkürzel:
| Taste | Funktion |
|---|---|
q | Beenden |
d | Delta-Modus (nur Änderungen) |
e | Prozesse ein-/ausklappen |
h | Hilfe |
p | Nach Prozess sortieren |
b | Nach Bytes sortieren |
Ausgabe verstehen:
bytes_in bytes_out rx_dupe ...
Safari.1234 1.2MB 45.6KB 0
tcp4 192.168.1.100:52341 -> 93.184.216.34:443 512KB 12KB
Chrome.5678 800KB 123.4KB 0
Praktische Beispiele:
# Top-Netzwerknutzer
nettop -l 1 -t wifi | head -20
# Verbindungen eines Prozesses
nettop -p Safari -l 1
# Bandbreite überwachen
watch -n 1 "nettop -l 1 -d | head -15"
Alternativen:
# lsof für Netzwerkverbindungen
lsof -i -n -P
# netstat
netstat -an -p tcp
# Aktivitätsmonitor CLI (Netzwerk-Tab)
nettop -c state,bytes_in,bytes_out -l 1
2 Signale
Signale sind der primäre Mechanismus zur Kommunikation mit Prozessen unter Unix. Sie können Prozesse beenden, pausieren, fortsetzen oder benutzerdefinierte Aktionen auslösen.
2.1 Signal-Übersicht (SIGTERM, SIGKILL, SIGHUP, …)
Wichtige Signale:
| Signal | Nummer | Beschreibung | Abfangbar |
|---|---|---|---|
SIGHUP | 1 | Hangup (Terminal geschlossen) | Ja |
SIGINT | 2 | Interrupt (Ctrl+C) | Ja |
SIGQUIT | 3 | Quit mit Core-Dump (Ctrl+) | Ja |
SIGKILL | 9 | Sofort beenden (nicht abfangbar!) | Nein |
SIGTERM | 15 | Sauber beenden (Standard) | Ja |
SIGSTOP | 17 | Prozess anhalten | Nein |
SIGTSTP | 18 | Terminal Stop (Ctrl+Z) | Ja |
SIGCONT | 19 | Fortsetzen | Ja |
SIGUSR1 | 30 | Benutzerdefiniert 1 | Ja |
SIGUSR2 | 31 | Benutzerdefiniert 2 | Ja |
SIGCHLD | 20 | Kind-Prozess beendet | Ja |
SIGALRM | 14 | Timer abgelaufen | Ja |
SIGPIPE | 13 | Schreiben in geschlossene Pipe | Ja |
Alle Signale anzeigen:
kill -l
# HUP INT QUIT ILL TRAP ABRT EMT FPE KILL BUS SEGV SYS PIPE ALRM TERM ...
Signal-Verhalten:
| Signal | Typische Reaktion |
|---|---|
| SIGTERM | Sauberes Herunterfahren, Aufräumen |
| SIGKILL | Sofortiger Tod, keine Aufräumarbeiten |
| SIGHUP | Konfiguration neu laden (Daemons) |
| SIGINT | Interaktiver Abbruch |
| SIGSTOP/CONT | Pausieren/Fortsetzen |
Best Practice:
1. Erst SIGTERM (15) versuchen – gibt Prozess Zeit zum Aufräumen
2. Warten (einige Sekunden)
3. Falls nötig: SIGKILL (9) – als letzter Ausweg
2.2 kill – Signale an Prozesse senden
Trotz des Namens kann kill alle Signale senden, nicht nur beenden.
Syntax:
kill [-SIGNAL] PID...
Grundlegende Nutzung:
# Standard: SIGTERM (15)
kill 1234
# SIGKILL (sofort beenden)
kill -9 1234
kill -KILL 1234
# SIGHUP (Konfiguration neu laden)
kill -1 1234
kill -HUP 1234
# SIGSTOP (pausieren)
kill -STOP 1234
# SIGCONT (fortsetzen)
kill -CONT 1234
Mehrere Prozesse:
# Mehrere PIDs
kill 1234 5678 9012
# Alle Prozesse einer Gruppe
kill -TERM -1234 # Negative PID = Prozessgruppe
# Mit $! (letzter Hintergrundprozess)
sleep 100 &
kill $!
Existenz prüfen:
# Signal 0 prüft nur, ob Prozess existiert
kill -0 1234 && echo "Prozess existiert" || echo "Nicht gefunden"
2.3 kill -s – Signal nach Name
Signale können auch mit -s und Namen angegeben werden.
Syntax:
kill -s SIGNALNAME PID
Beispiele:
# Nach Name
kill -s TERM 1234
kill -s KILL 1234
kill -s HUP 1234
# Äquivalent zu
kill -TERM 1234
kill -15 1234
Alle verfügbaren Signalnamen:
kill -l
# 1) SIGHUP 2) SIGINT 3) SIGQUIT 4) SIGILL
# 5) SIGTRAP 6) SIGABRT 7) SIGEMT 8) SIGFPE
# 9) SIGKILL 10) SIGBUS 11) SIGSEGV 12) SIGSYS
# ...
2.4 pkill – Prozesse nach Name beenden
pkill sendet Signale an Prozesse basierend auf Namen oder anderen Kriterien.
Syntax:
pkill [Optionen] MUSTER
Grundlegende Nutzung:
# Nach Prozessname (Teilmatch)
pkill Safari
pkill -9 Safari # SIGKILL
# Exakter Name
pkill -x Safari
# Case-insensitive
pkill -i safari
Erweiterte Filter:
# Nach Benutzer
pkill -u max Safari
# Nach Gruppe
pkill -g staff Firefox
# Nach Terminal
pkill -t ttys001
# Ältere als X Sekunden
pkill -o -older 3600 process
# Jüngste Instanz
pkill -n process
# Eltern-PID
pkill -P 1234
Optionen:
| Option | Beschreibung |
|---|---|
-SIGNAL | Signal angeben (-9, -HUP, etc.) |
-u USER | Nach Benutzer |
-g GROUP | Nach Gruppe |
-t TTY | Nach Terminal |
-P PPID | Nach Eltern-PID |
-x | Exakter Name |
-i | Case-insensitive |
-n | Nur neuester Prozess |
-o | Nur ältester Prozess |
-f | Vollständige Kommandozeile matchen |
Trockenlauf mit pgrep:
# Erst prüfen was gematcht wird
pgrep -l Safari
# 1234 Safari
# Dann killen
pkill Safari
2.5 killall – Alle Prozesse eines Namens
killall beendet alle Prozesse mit exakt dem angegebenen Namen.
Syntax:
killall [Optionen] PROZESSNAME
Grundlegende Nutzung:
# Alle Safari-Prozesse beenden
killall Safari
# Mit SIGKILL
killall -9 Safari
killall -KILL Safari
# Mit SIGHUP
killall -HUP nginx
Optionen:
# Interaktiv (Bestätigung)
killall -i Safari
# Verbose
killall -v Safari
# Nach Benutzer
killall -u max Safari
# Ältere als X Sekunden
killall -o 1h Safari # älter als 1 Stunde
killall -y 5m Safari # jünger als 5 Minuten
# Regex
killall -r "^Safari"
Optionen-Übersicht:
| Option | Beschreibung |
|---|---|
-SIGNAL | Signal angeben |
-v | Verbose |
-i | Interaktiv (fragen) |
-u USER | Nach Benutzer |
-o TIME | Älter als |
-y TIME | Jünger als |
-r | Regex-Match |
-z | Auch Zombies |
Unterschied pkill vs killall:
| Merkmal | pkill | killall |
|---|---|---|
| Matching | Teilstring/Regex | Exakter Name (Standard) |
| Kommandozeile | Mit -f | Nein |
| Filter | Umfangreich | Basis |
| Portabilität | POSIX-ähnlich | BSD/macOS |
Praktische Beispiele:
# Alle Python-Prozesse
killall python3
# Alle Hintergrund-Jobs des Users
killall -u $(whoami)
# Nginx graceful restart
killall -HUP nginx
# Alle Node.js-Prozesse älter als 1 Tag
killall -o 24h node
3 Prozessgruppen & Jobs
3.1 Vordergrund- und Hintergrundprozesse
Vordergrundprozess:
- Blockiert das Terminal
- Empfängt Tastatureingaben
- Ctrl+C sendet SIGINT
- Ctrl+Z sendet SIGTSTP (pausieren)
Hintergrundprozess:
- Terminal bleibt nutzbar
- Kein direkter Tastaturzugriff
- Läuft parallel
Prozess im Hintergrund starten:
# Mit & am Ende
long-running-command &
# Beispiel
sleep 100 &
# [1] 12345 (Job-Nummer und PID)
Jobs verwalten:
# Alle Jobs anzeigen
jobs
# [1] + running sleep 100
# [2] - running another-command
# Mit PIDs
jobs -p
# Mit Status
jobs -l
Zwischen Vorder- und Hintergrund wechseln:
# Prozess starten
sleep 100
# Pausieren mit Ctrl+Z
^Z
# [1] + 12345 suspended sleep 100
# Im Hintergrund fortsetzen
bg
bg %1 # Bestimmter Job
# In den Vordergrund holen
fg
fg %1 # Bestimmter Job
Job-Referenzen:
| Referenz | Bedeutung |
|---|---|
%1 | Job Nummer 1 |
%+ oder %% | Aktueller Job |
%- | Vorheriger Job |
%string | Job der mit “string” beginnt |
%?string | Job der “string” enthält |
Beispiele:
# Drei Jobs starten
sleep 100 &
vim file.txt &
python script.py &
# Jobs anzeigen
jobs
# [1] running sleep 100
# [2] - running vim file.txt
# [3] + running python script.py
# Vim in Vordergrund
fg %2
fg %vi # Nach Name
# Python beenden
kill %3
kill %?python
3.2 nohup – Prozesse vom Terminal lösen
nohup (No Hangup) verhindert, dass ein Prozess beendet wird wenn das Terminal geschlossen wird.
Grundlegende Nutzung:
# Prozess startet und läuft nach Terminal-Schließung weiter
nohup command &
# Beispiel
nohup ./long-script.sh &
# nohup: ignoring input and appending output to 'nohup.out'
Ausgabe umleiten:
# Standard: Ausgabe geht nach nohup.out
nohup command &
# Eigene Log-Datei
nohup command > output.log 2>&1 &
# Ausgabe verwerfen
nohup command > /dev/null 2>&1 &
Typischer Workflow:
# 1. Prozess mit nohup starten
nohup ./backup.sh > backup.log 2>&1 &
# 2. PID notieren
echo $!
# 12345
# 3. Terminal schließen (Prozess läuft weiter)
exit
# 4. Später: Status prüfen
ps -p 12345
tail -f backup.log
Praktisches Beispiel:
# Langer Download
nohup wget -c https://example.com/large-file.zip > wget.log 2>&1 &
# Server starten
nohup python -m http.server 8000 > server.log 2>&1 &
# Backup-Skript
nohup rsync -avz /source/ /backup/ > rsync.log 2>&1 &
3.3 disown – Jobs aus Shell entfernen
disown entfernt einen Job aus der Job-Tabelle der Shell, sodass er nicht beendet wird wenn die Shell beendet wird.
Unterschied zu nohup:
| Merkmal | nohup | disown |
|---|---|---|
| Zeitpunkt | Vor dem Start | Nach dem Start |
| SIGHUP ignorieren | Ja | Mit -h |
| Job-Tabelle | Normal | Entfernt |
| Ausgabe | nohup.out | Unverändert |
Grundlegende Nutzung:
# Job starten
long-command &
# Aus Job-Tabelle entfernen
disown
# Bestimmten Job
disown %1
# SIGHUP ignorieren (Job bleibt in Liste)
disown -h %1
# Alle Jobs
disown -a
Typischer Workflow:
# 1. Prozess gestartet (vergessen nohup zu nutzen)
./script.sh
^Z
bg
# 2. Jetzt disown um ihn zu behalten
disown -h %1
# 3. Shell kann sicher beendet werden
exit
Praktisches Beispiel:
# Server versehentlich ohne nohup gestartet
python server.py &
# Oops! Terminal schließen würde Server beenden
# Lösung: disown
disown -h
# Jetzt sicher Terminal schließen
exit
Nachträglich von Terminal lösen:
# Prozess läuft im Vordergrund
long-running-process
# Ctrl+Z pausiert
^Z
# [1] + suspended long-running-process
# Im Hintergrund fortsetzen
bg
# Von Shell lösen
disown -h
# Terminal kann geschlossen werden
3.4 Prozessgruppen und Session-IDs
Konzepte:
Session (SID)
└── Prozessgruppe (PGID)
└── Prozess (PID)
└── Prozess (PID)
└── Prozessgruppe (PGID)
└── Prozess (PID)
| Begriff | Beschreibung |
|---|---|
| PID | Process ID – eindeutige Prozess-Kennung |
| PPID | Parent PID – PID des Elternprozesses |
| PGID | Process Group ID – Gruppe zusammengehöriger Prozesse |
| SID | Session ID – Login-Session |
IDs anzeigen:
# Aktuelle IDs
echo "PID: $$"
echo "PPID: $PPID"
# Mit ps
ps -o pid,ppid,pgid,sid,comm
# Für bestimmten Prozess
ps -o pid,ppid,pgid,sid,comm -p 1234
Prozessgruppen verstehen:
# Pipeline erstellt Prozessgruppe
cat file | grep pattern | sort
# Alle drei Prozesse haben gleiche PGID
ps -o pid,pgid,comm
# PID PGID COMM
# 1001 1001 cat
# 1002 1001 grep
# 1003 1001 sort
Signal an Prozessgruppe senden:
# Negative PID = Prozessgruppe
kill -TERM -1001
# Alle Prozesse der Gruppe beenden
kill -9 -$(ps -o pgid= -p $PID)
Sessions verstehen:
- Jedes Terminal startet eine neue Session
- Session-Leader ist meist die Shell
- Alle von der Shell gestarteten Prozesse gehören zur Session
# Neue Session erstellen (für Daemons)
setsid command
# Prozess von Terminal lösen
setsid ./daemon.sh
Prozessbaum anzeigen:
# Mit pstree (falls installiert)
brew install pstree
pstree
# Mit ps
ps -axjf
# Kinder eines Prozesses
pgrep -P 1234
ps --ppid 1234
Waisen- und Zombie-Prozesse:
| Typ | Beschreibung | Status |
|---|---|---|
| Waise | Elternprozess beendet, init übernimmt | Normal |
| Zombie | Beendet, aber Eltern hat Exit-Code nicht gelesen | Z in ps |
# Zombies finden
ps aux | awk '$8=="Z"'
# Oder
ps -eo pid,ppid,stat,comm | grep Z
Zombie-Prozesse bereinigen:
Zombies können nicht direkt beendet werden. Lösungen:
# 1. SIGCHLD an Elternprozess
kill -SIGCHLD $(ps -o ppid= -p $ZOMBIE_PID)
# 2. Elternprozess beenden (Zombie wird von init übernommen)
kill $(ps -o ppid= -p $ZOMBIE_PID)
# 3. Im schlimmsten Fall: Neustart
Daemon-Muster (doppelter Fork):
#!/bin/zsh
# daemon.sh - Prozess vollständig vom Terminal lösen
(
# Erster Fork
cd /
umask 0
exec setsid ./actual-daemon.sh &
) &
# Shell kann sofort beenden
exit 0
Zusammenfassung Job-Control:
# Starten
command & # Im Hintergrund
nohup command & # Immun gegen SIGHUP
# Kontrolle
jobs # Jobs anzeigen
fg %n # In Vordergrund
bg %n # Im Hintergrund fortsetzen
Ctrl+Z # Pausieren
Ctrl+C # Abbrechen
# Loslösen
disown %n # Aus Job-Liste entfernen
disown -h %n # SIGHUP ignorieren
# Beenden
kill %n # Job beenden
kill -9 %n # Erzwungen
Sicherheit & Verschlüsselung
Dieses Kapitel behandelt Werkzeuge für Verschlüsselung, digitale Signaturen und sichere Systemadministration.
1 GPG (GnuPG)
GnuPG (GNU Privacy Guard) ist die freie Implementierung des OpenPGP-Standards für asymmetrische Verschlüsselung und digitale Signaturen.
1.1 Installation und Schlüsselerstellung
Installation:
brew install gnupg
# Version prüfen
gpg --version
Optionale GUI-Tools:
# GPG Suite (macOS GUI)
brew install --cask gpg-suite
# Oder nur Pinentry für Passphrase-Eingabe
brew install pinentry-mac
Schlüsselpaar generieren:
# Interaktiver Assistent
gpg --full-generate-key
# Ausgabe:
# Bitte wählen Sie, welche Art von Schlüssel Sie möchten:
# (1) RSA und RSA
# (2) DSA und Elgamal
# (3) DSA (nur signieren)
# (4) RSA (nur signieren)
# (9) ECC (signieren und verschlüsseln) *Standard*
# (10) ECC (nur signieren)
# Ihre Auswahl? 9
Empfohlene Einstellungen:
| Einstellung | Empfehlung |
|---|---|
| Algorithmus | ECC (Curve 25519) oder RSA 4096 |
| Gültigkeit | 1-2 Jahre (kann verlängert werden) |
| Name | Vollständiger Name |
| Haupt-E-Mail-Adresse | |
| Passphrase | Stark und einzigartig |
Schnelle Schlüsselerstellung:
# Schnell mit Defaults
gpg --quick-generate-key "Max Mustermann <max@example.com>"
# Mit spezifischen Optionen
gpg --quick-generate-key "Max Mustermann <max@example.com>" rsa4096 cert 2y
Schlüssel nach Erstellung:
# Öffentliche Schlüssel anzeigen
gpg --list-keys
gpg -k
# Private Schlüssel anzeigen
gpg --list-secret-keys
gpg -K
# Ausgabe:
# pub ed25519 2024-01-15 [SC] [expires: 2026-01-15]
# ABCD1234EFGH5678IJKL9012MNOP3456QRST7890
# uid [ultimate] Max Mustermann <max@example.com>
# sub cv25519 2024-01-15 [E] [expires: 2026-01-15]
Schlüssel-IDs verstehen:
| Länge | Beispiel | Verwendung |
|---|---|---|
| Fingerprint (40) | ABCD1234...7890 | Vollständige Identifikation |
| Long ID (16) | MNOP3456QRST7890 | Eindeutig genug |
| Short ID (8) | QRST7890 | Veraltet, Kollisionsgefahr |
max@example.com | Bequem, aber nicht eindeutig |
1.2 Dateien verschlüsseln und entschlüsseln
Asymmetrisch verschlüsseln (für Empfänger):
# Für einen Empfänger
gpg --encrypt --recipient max@example.com datei.txt
# Ergebnis: datei.txt.gpg
# Kurzform
gpg -e -r max@example.com datei.txt
# Für mehrere Empfänger
gpg -e -r alice@example.com -r bob@example.com datei.txt
# Mit ASCII-Armor (Textformat)
gpg -e -a -r max@example.com datei.txt
# Ergebnis: datei.txt.asc
# Ausgabedatei angeben
gpg -e -r max@example.com -o geheim.gpg datei.txt
Asymmetrisch entschlüsseln:
# Standard (fragt nach Passphrase)
gpg --decrypt datei.txt.gpg
# Ausgabe auf stdout
# In Datei speichern
gpg -d datei.txt.gpg > datei.txt
gpg -d -o datei.txt datei.txt.gpg
# Kurzform
gpg datei.txt.gpg
# Erstellt automatisch datei.txt
Symmetrisch verschlüsseln (mit Passwort):
# Mit Passwort verschlüsseln
gpg --symmetric datei.txt
gpg -c datei.txt
# Fragt nach Passphrase, erstellt datei.txt.gpg
# Mit spezifischem Algorithmus
gpg -c --cipher-algo AES256 datei.txt
# Als ASCII
gpg -c -a datei.txt
Symmetrisch entschlüsseln:
gpg -d datei.txt.gpg
gpg -d -o datei.txt datei.txt.gpg
Kombiniert (symmetrisch + asymmetrisch):
# Sowohl mit Passwort als auch für Empfänger
gpg -c -e -r max@example.com datei.txt
Verzeichnisse verschlüsseln:
# Erst tar, dann gpg
tar -czvf - ordner/ | gpg -c -o ordner.tar.gz.gpg
# Entschlüsseln und entpacken
gpg -d ordner.tar.gz.gpg | tar -xzvf -
1.3 Signaturen erstellen und prüfen
Digitale Signaturen beweisen Authentizität und Integrität.
Datei signieren:
# Detached Signature (separate .sig Datei)
gpg --detach-sign datei.txt
# Ergebnis: datei.txt.sig
# ASCII-Format
gpg --detach-sign -a datei.txt
# Ergebnis: datei.txt.asc
# Klartext-Signatur (Signatur + Original)
gpg --clearsign datei.txt
# Ergebnis: datei.txt.asc (enthält Original + Signatur)
# Signatur eingebettet (binär)
gpg --sign datei.txt
# Ergebnis: datei.txt.gpg
Signatur prüfen:
# Detached Signature prüfen
gpg --verify datei.txt.sig datei.txt
# Ausgabe bei gültiger Signatur:
# gpg: Signature made Mon Jan 15 10:30:00 2024 CET
# gpg: using EDDSA key ABCD...7890
# gpg: Good signature from "Max Mustermann <max@example.com>"
# Clearsign oder eingebettete Signatur
gpg --verify datei.txt.asc
# Signierte Datei extrahieren und prüfen
gpg --decrypt datei.txt.gpg
Signieren und Verschlüsseln:
# Verschlüsseln + Signieren
gpg -e -s -r empfaenger@example.com datei.txt
# Entschlüsseln prüft automatisch Signatur
gpg -d datei.txt.gpg
Git-Commits signieren:
# GPG-Schlüssel für Git konfigurieren
git config --global user.signingkey ABCD1234EFGH5678
# Einzelnen Commit signieren
git commit -S -m "Signierter Commit"
# Alle Commits signieren
git config --global commit.gpgsign true
# Signaturen anzeigen
git log --show-signature
1.4 Schlüsselverwaltung
Schlüssel exportieren:
# Öffentlichen Schlüssel exportieren (zum Teilen)
gpg --export -a max@example.com > publickey.asc
gpg --export --armor ABCD1234 > publickey.asc
# Privaten Schlüssel exportieren (Backup!)
gpg --export-secret-keys -a max@example.com > privatekey.asc
# Alle Schlüssel exportieren
gpg --export -a > all-public-keys.asc
gpg --export-secret-keys -a > all-private-keys.asc
Schlüssel importieren:
# Öffentlichen Schlüssel importieren
gpg --import publickey.asc
# Privaten Schlüssel importieren
gpg --import privatekey.asc
# Von Keyserver
gpg --keyserver hkps://keys.openpgp.org --recv-keys ABCD1234EFGH5678
Schlüssel auf Keyserver hochladen:
gpg --keyserver hkps://keys.openpgp.org --send-keys ABCD1234EFGH5678
Schlüssel bearbeiten:
# Interaktiver Editor
gpg --edit-key max@example.com
# Verfügbare Befehle:
# uid - UID auswählen
# trust - Vertrauensstufe setzen
# expire - Ablaufdatum ändern
# passwd - Passphrase ändern
# adduid - E-Mail hinzufügen
# deluid - E-Mail entfernen
# save - Speichern und beenden
# quit - Ohne Speichern beenden
Vertrauensstufen:
| Stufe | Bedeutung |
|---|---|
| Unknown | Nicht bewertet |
| Never | Nicht vertrauenswürdig |
| Marginal | Teilweise vertrauenswürdig |
| Full | Voll vertrauenswürdig |
| Ultimate | Eigener Schlüssel |
# Vertrauen setzen
gpg --edit-key alice@example.com
gpg> trust
# Stufe wählen
gpg> save
Schlüssel widerrufen:
# Widerrufszertifikat erstellen (bei Erstellung!)
gpg --gen-revoke ABCD1234 > revoke.asc
# Schlüssel widerrufen (wenn kompromittiert)
gpg --import revoke.asc
gpg --keyserver hkps://keys.openpgp.org --send-keys ABCD1234
Schlüssel löschen:
# Öffentlichen Schlüssel löschen
gpg --delete-keys ABCD1234
# Privaten Schlüssel löschen
gpg --delete-secret-keys ABCD1234
# Beides
gpg --delete-secret-and-public-keys ABCD1234
GPG-Agent konfigurieren:
# ~/.gnupg/gpg-agent.conf
default-cache-ttl 3600
max-cache-ttl 86400
pinentry-program /opt/homebrew/bin/pinentry-mac
# Agent neu starten
gpgconf --kill gpg-agent
gpg-agent --daemon
2 OpenSSL
OpenSSL ist das Schweizer Taschenmesser für Kryptographie: Zertifikate, Verschlüsselung, Hashes und mehr.
2.1 Zertifikate anzeigen und prüfen
Zertifikat einer Website anzeigen:
# Zertifikat abrufen und anzeigen
openssl s_client -connect example.com:443 -servername example.com </dev/null 2>/dev/null | \
openssl x509 -noout -text
# Nur wichtige Infos
openssl s_client -connect example.com:443 -servername example.com </dev/null 2>/dev/null | \
openssl x509 -noout -subject -issuer -dates
# Ausgabe:
# subject=CN = example.com
# issuer=C = US, O = DigiCert Inc, CN = DigiCert TLS RSA SHA256 2020 CA1
# notBefore=Jan 15 00:00:00 2024 GMT
# notAfter=Jan 15 23:59:59 2025 GMT
Lokales Zertifikat anzeigen:
# PEM-Datei
openssl x509 -in certificate.pem -noout -text
# DER-Format
openssl x509 -in certificate.der -inform DER -noout -text
# Nur bestimmte Felder
openssl x509 -in cert.pem -noout -subject
openssl x509 -in cert.pem -noout -issuer
openssl x509 -in cert.pem -noout -dates
openssl x509 -in cert.pem -noout -fingerprint
openssl x509 -in cert.pem -noout -serial
Zertifikatskette prüfen:
# Kette verifizieren
openssl verify -CAfile ca-bundle.crt certificate.pem
# Mit Zwischenzertifikaten
openssl verify -CAfile root.crt -untrusted intermediate.crt server.crt
TLS-Verbindung testen:
# Verbindung und Handshake testen
openssl s_client -connect example.com:443
# Mit bestimmtem Protokoll
openssl s_client -connect example.com:443 -tls1_2
openssl s_client -connect example.com:443 -tls1_3
# Zertifikatskette anzeigen
openssl s_client -connect example.com:443 -showcerts
# SNI (Server Name Indication)
openssl s_client -connect server.com:443 -servername www.example.com
Ablaufdatum prüfen:
# Website-Zertifikat
echo | openssl s_client -connect example.com:443 -servername example.com 2>/dev/null | \
openssl x509 -noout -enddate
# notAfter=Jan 15 23:59:59 2025 GMT
# Tage bis Ablauf
expiry=$(echo | openssl s_client -connect example.com:443 2>/dev/null | \
openssl x509 -noout -enddate | cut -d= -f2)
echo $(( ($(date -jf "%b %d %H:%M:%S %Y %Z" "$expiry" +%s) - $(date +%s)) / 86400 )) Tage
Selbstsigniertes Zertifikat erstellen:
# Schlüssel und Zertifikat in einem Schritt
openssl req -x509 -newkey rsa:4096 -keyout key.pem -out cert.pem -days 365 -nodes
# Mit spezifischen Angaben
openssl req -x509 -newkey rsa:4096 -keyout key.pem -out cert.pem -days 365 -nodes \
-subj "/CN=localhost/O=Development/C=DE"
2.2 Dateien verschlüsseln (symmetrisch)
Datei verschlüsseln:
# AES-256-CBC (empfohlen)
openssl enc -aes-256-cbc -salt -pbkdf2 -in datei.txt -out datei.enc
# Mit explizitem Passwort (unsicher für Skripte!)
openssl enc -aes-256-cbc -salt -pbkdf2 -in datei.txt -out datei.enc -pass pass:geheim
# Passwort aus Datei
openssl enc -aes-256-cbc -salt -pbkdf2 -in datei.txt -out datei.enc -pass file:password.txt
# Base64-kodiert (für E-Mail etc.)
openssl enc -aes-256-cbc -salt -pbkdf2 -a -in datei.txt -out datei.enc
Datei entschlüsseln:
# Standard
openssl enc -aes-256-cbc -d -pbkdf2 -in datei.enc -out datei.txt
# Base64-kodiert
openssl enc -aes-256-cbc -d -pbkdf2 -a -in datei.enc -out datei.txt
Verfügbare Algorithmen:
# Alle Cipher auflisten
openssl enc -list
# Empfohlene Algorithmen:
# aes-256-cbc - AES 256-bit, CBC-Modus
# aes-256-gcm - AES 256-bit, GCM-Modus (authentifiziert)
# chacha20 - ChaCha20 Stream-Cipher
Wichtige Optionen:
| Option | Beschreibung |
|---|---|
-e | Encrypt (Standard) |
-d | Decrypt |
-salt | Salt verwenden (Standard, wichtig!) |
-pbkdf2 | Moderne Key-Derivation (empfohlen) |
-iter N | PBKDF2-Iterationen |
-a | Base64-Encoding |
-in FILE | Eingabedatei |
-out FILE | Ausgabedatei |
-pass | Passwort-Quelle |
2.3 Hashes und Checksummen
Einzelne Datei hashen:
# SHA-256 (empfohlen)
openssl sha256 datei.txt
# SHA256(datei.txt)= abc123...
# Nur Hash (ohne Dateiname)
openssl sha256 -r datei.txt | cut -d' ' -f1
# Verschiedene Algorithmen
openssl md5 datei.txt # veraltet
openssl sha1 datei.txt # veraltet
openssl sha256 datei.txt # empfohlen
openssl sha384 datei.txt
openssl sha512 datei.txt
Alternative: Standard-Tools:
# macOS eingebaute Tools
shasum -a 256 datei.txt
md5 datei.txt
# SHA-256
shasum -a 256 datei.txt
# abc123... datei.txt
# SHA-512
shasum -a 512 datei.txt
Checksumme prüfen:
# Checksummen-Datei erstellen
shasum -a 256 *.zip > checksums.sha256
# Prüfen
shasum -a 256 -c checksums.sha256
# file1.zip: OK
# file2.zip: OK
HMAC (Hash mit Schlüssel):
# HMAC-SHA256
openssl dgst -sha256 -hmac "geheimer-schluessel" datei.txt
# Aus Datei
openssl dgst -sha256 -hmac "$(cat key.txt)" datei.txt
String hashen:
# String statt Datei
echo -n "zu hashender text" | openssl sha256
echo -n "zu hashender text" | shasum -a 256
# Wichtig: -n verhindert Newline am Ende!
Passwort-Hash erstellen:
# Für /etc/shadow-ähnliche Hashes
openssl passwd -6 "meinpasswort" # SHA-512
openssl passwd -5 "meinpasswort" # SHA-256
openssl passwd -1 "meinpasswort" # MD5 (veraltet)
# Mit Salt
openssl passwd -6 -salt "randomsalt" "meinpasswort"
2.4 Zufallsdaten generieren
Zufällige Bytes:
# 32 Bytes als Hex
openssl rand -hex 32
# a1b2c3d4e5f6...
# 32 Bytes als Base64
openssl rand -base64 32
# QUJDREVGR0hJSktMTU5PUFE=
# In Datei
openssl rand -out random.bin 256
# Für Passwörter (URL-safe)
openssl rand -base64 24 | tr -dc 'a-zA-Z0-9' | head -c 32
Sichere Passwörter generieren:
# Zufälliges Passwort
openssl rand -base64 18
# kQ7xY9mN2pL4vR6t8wZa
# Alphanumerisch
openssl rand -base64 32 | tr -dc 'a-zA-Z0-9' | head -c 16
# Mit Sonderzeichen
openssl rand -base64 32 | head -c 20
Alternative: macOS security:
# Zufälliges Passwort mit Keychain-Tool
security random-string 20
# UUID generieren
uuidgen
Für Kryptographie:
# AES-256 Schlüssel (32 Bytes)
openssl rand -hex 32
# IV für AES (16 Bytes)
openssl rand -hex 16
# Salt
openssl rand -hex 8
3 Sichere Administration
3.1 sudoedit – Dateien sicher bearbeiten
sudoedit (oder sudo -e) bearbeitet Dateien sicher, ohne den Editor als root zu starten.
Problem mit sudo vim:
# UNSICHER: vim läuft als root
sudo vim /etc/hosts
# vim-Plugins, Shell-Escapes etc. laufen alle als root!
Lösung mit sudoedit:
# SICHER: Editor läuft als normaler User
sudoedit /etc/hosts
# oder
sudo -e /etc/hosts
Wie es funktioniert:
- Erstellt temporäre Kopie der Datei
- Öffnet Editor als normaler Benutzer
- Kopiert Änderungen nach Schließen zurück (als root)
Editor konfigurieren:
# In ~/.zshrc
export SUDO_EDITOR="nano"
# oder
export SUDO_EDITOR="vim"
export SUDO_EDITOR="code --wait"
# Alternativ
export VISUAL="nano"
export EDITOR="nano"
Vorteile:
| sudo vim | sudoedit |
|---|---|
| Editor als root | Editor als User |
| Plugins als root | Plugins als User |
| Shell-Escape = root | Shell-Escape = User |
| Unsicher | Sicher |
3.2 /etc/sudoers und visudo
Die Datei /etc/sudoers kontrolliert sudo-Berechtigungen. Sie darf nur mit visudo bearbeitet werden.
visudo verwenden:
# Konfiguration bearbeiten (prüft Syntax!)
sudo visudo
# Mit spezifischem Editor
sudo EDITOR=nano visudo
# Syntax einer Datei prüfen
sudo visudo -c
sudo visudo -cf /etc/sudoers.d/custom
Warum visudo?
- Prüft Syntax vor dem Speichern
- Verhindert gleichzeitige Bearbeitung
- Fehlerhafte Syntax = kein sudo mehr möglich!
sudoers-Syntax:
# Grundformat
WER WO = (ALS_WER) WAS
# Beispiele
root ALL=(ALL:ALL) ALL
%admin ALL=(ALL) ALL
max ALL=(ALL) NOPASSWD: ALL
Felder erklärt:
| Feld | Bedeutung | Beispiel |
|---|---|---|
| WER | Benutzer oder %gruppe | max, %admin |
| WO | Hosts | ALL, localhost |
| ALS_WER | Zielbenutzer:gruppe | (ALL), (root) |
| WAS | Erlaubte Befehle | ALL, /usr/bin/apt |
Praktische Beispiele:
# Benutzer max darf alles ohne Passwort
max ALL=(ALL) NOPASSWD: ALL
# Gruppe developers darf Docker ohne Passwort
%developers ALL=(ALL) NOPASSWD: /usr/bin/docker, /usr/bin/docker-compose
# Benutzer backup darf nur rsync als root
backup ALL=(root) NOPASSWD: /usr/bin/rsync
# Benutzer webadmin darf Webserver neustarten
webadmin ALL=(root) NOPASSWD: /usr/bin/systemctl restart nginx, /usr/bin/systemctl restart apache2
# Umgebungsvariablen erhalten
Defaults env_keep += "HOME"
Defaults env_keep += "SSH_AUTH_SOCK"
Include-Dateien:
# Separate Dateien in /etc/sudoers.d/
sudo visudo -f /etc/sudoers.d/developers
# In /etc/sudoers aktiviert durch:
@includedir /etc/sudoers.d
# oder (ältere Syntax)
#includedir /etc/sudoers.d
Aliase definieren:
# Benutzer-Aliase
User_Alias ADMINS = alice, bob, carol
User_Alias DEVELOPERS = dev1, dev2, dev3
# Befehls-Aliase
Cmnd_Alias SERVICES = /usr/bin/systemctl restart *, /usr/bin/systemctl status *
Cmnd_Alias DOCKER = /usr/bin/docker, /usr/bin/docker-compose
Cmnd_Alias NETWORKING = /sbin/ifconfig, /sbin/route, /usr/bin/ping
# Verwendung
ADMINS ALL=(ALL) ALL
DEVELOPERS ALL=(root) NOPASSWD: DOCKER, SERVICES
3.3 Einschränkungen mit sudo
Befehle einschränken:
# Nur bestimmte Befehle
max ALL=(root) /usr/bin/apt update, /usr/bin/apt upgrade
# Mit Wildcards
max ALL=(root) /usr/bin/systemctl restart nginx*
# Ohne Argumente
max ALL=(root) /usr/bin/reboot ""
# Bestimmte Argumente verbieten
max ALL=(root) /usr/bin/rm, !/usr/bin/rm -rf /
NOPASSWD vs PASSWD:
# Ohne Passwort
max ALL=(ALL) NOPASSWD: /usr/bin/docker
# Mit Passwort (Standard)
max ALL=(ALL) PASSWD: /usr/bin/visudo
# Gemischt
max ALL=(ALL) PASSWD: ALL, NOPASSWD: /usr/bin/docker
Verbote (!):
# Alles außer bestimmte Befehle
max ALL=(ALL) ALL, !/bin/su, !/bin/bash, !/usr/bin/passwd root
# Shell-Escape verhindern
max ALL=(ALL) NOEXEC: /usr/bin/vim
NOEXEC – Shell-Escapes verhindern:
# Verhindert dass vim Shell startet
max ALL=(root) NOEXEC: /usr/bin/vim
Logging:
# Alle Befehle loggen
Defaults log_input, log_output
Defaults logfile="/var/log/sudo.log"
# I/O-Logging
Defaults iolog_dir="/var/log/sudo-io"
Timeout-Einstellungen:
# Passwort-Timeout (Minuten)
Defaults timestamp_timeout=15
# Sofort Passwort verlangen
Defaults timestamp_timeout=0
# Nie wieder fragen (Session)
Defaults timestamp_timeout=-1
# Anzahl Passwort-Versuche
Defaults passwd_tries=3
Sicherheits-Empfehlungen:
# Sichere PATH-Einstellung
Defaults secure_path="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
# Root-Passwort bei Authentifizierung verlangen
Defaults rootpw
# TTY erforderlich (verhindert Skript-Missbrauch)
Defaults requiretty
# Insults bei falschem Passwort (Spaß)
Defaults insults
Sudo-Berechtigungen prüfen:
# Eigene Berechtigungen anzeigen
sudo -l
# Ausgabe:
# User max may run the following commands on hostname:
# (ALL) ALL
# (root) NOPASSWD: /usr/bin/docker
# Für anderen Benutzer
sudo -l -U alice
Sudo-Session beenden:
# Timestamp zurücksetzen (Passwort wird wieder verlangt)
sudo -k
# Timestamp komplett löschen
sudo -K
Best Practices:
- Minimal notwendige Rechte: Nur spezifische Befehle erlauben
- Keine Shell-Befehle:
/bin/bash,/bin/suvermeiden - NOEXEC nutzen: Bei Editoren und Programmen mit Shell-Escape
- Separate Dateien:
/etc/sudoers.d/für Organisation - Logging aktivieren: Für Audit-Trail
- Regelmäßig prüfen:
sudo -lundvisudo -c
Cheatsheet sudoers:
# Format
USER HOST=(RUNAS) COMMAND
# Beispiele
root ALL=(ALL:ALL) ALL # root darf alles
%admin ALL=(ALL) ALL # Gruppe admin darf alles
max ALL=(ALL) NOPASSWD: ALL # max ohne Passwort
deploy ALL=(root) /usr/bin/docker # deploy nur docker
backup ALL=(root) NOPASSWD: /usr/bin/rsync # backup rsync ohne PW
# Verbote
max ALL=(ALL) ALL, !/bin/su # alles außer su
# Aliase
User_Alias DEVS = alice, bob
Cmnd_Alias DOCKER = /usr/bin/docker
DEVS ALL=(root) NOPASSWD: DOCKER
# Sicherheit
Defaults requiretty
Defaults timestamp_timeout=5
Defaults secure_path="..."
macOS-Integration
macOS bietet viele Terminal-Befehle zur Integration mit dem Betriebssystem: Zwischenablage, Finder, Systemeinstellungen und mehr.
1 Zwischenablage
Die macOS-Zwischenablage (Pasteboard) ist vollständig vom Terminal aus zugänglich.
1.1 pbcopy – In Zwischenablage kopieren
pbcopy kopiert stdin in die Zwischenablage.
Grundlegende Nutzung:
# Text kopieren
echo "Hallo Welt" | pbcopy
# Dateiinhalt kopieren
cat datei.txt | pbcopy
pbcopy < datei.txt
# Befehlsausgabe kopieren
pwd | pbcopy
ls -la | pbcopy
# Mehrere Zeilen
cat << EOF | pbcopy
Zeile 1
Zeile 2
Zeile 3
EOF
Optionen:
# Standard-Pasteboard (wie Cmd+C)
echo "text" | pbcopy
# Find-Pasteboard (für Cmd+G Suche)
echo "suchtext" | pbcopy -pboard find
# Ruler-Pasteboard
echo "data" | pbcopy -pboard ruler
1.2 pbpaste – Aus Zwischenablage einfügen
pbpaste gibt den Inhalt der Zwischenablage auf stdout aus.
Grundlegende Nutzung:
# In Terminal ausgeben
pbpaste
# In Datei speichern
pbpaste > datei.txt
# An Datei anhängen
pbpaste >> datei.txt
# Als Variable
content=$(pbpaste)
echo "$content"
Optionen:
# Standard-Pasteboard
pbpaste
# Find-Pasteboard
pbpaste -pboard find
# Nur Plain Text (falls Rich Text kopiert)
pbpaste -Prefer txt
1.3 Praxisbeispiele mit Pipes
Textverarbeitung:
# Kopierte URLs bereinigen
pbpaste | tr -d '\n' | pbcopy
# Großbuchstaben
pbpaste | tr '[:lower:]' '[:upper:]' | pbcopy
# Zeilen sortieren
pbpaste | sort | pbcopy
# Duplikate entfernen
pbpaste | sort -u | pbcopy
# Leerzeichen trimmen
pbpaste | sed 's/^[:space:](:space:.md)*//;s/[:space:](:space:.md)*$//' | pbcopy
# Zeilen nummerieren
pbpaste | nl | pbcopy
Entwicklung:
# Git diff kopieren
git diff | pbcopy
# JSON formatieren
pbpaste | jq . | pbcopy
# Base64 kodieren
pbpaste | base64 | pbcopy
# Base64 dekodieren
pbpaste | base64 -d | pbcopy
# MD5-Hash von Clipboard-Inhalt
pbpaste | md5
# URL-Encoding
pbpaste | python3 -c "import sys, urllib.parse; print(urllib.parse.quote(sys.stdin.read().strip()))" | pbcopy
Pfade und Dateien:
# Aktuellen Pfad kopieren
pwd | pbcopy
# Dateiliste kopieren
ls -1 | pbcopy
# Voller Pfad einer Datei
realpath datei.txt | pbcopy
# SSH Public Key kopieren
cat ~/.ssh/id_ed25519.pub | pbcopy
Nützliche Aliase:
# ~/.zshrc
# Clipboard-Shortcuts
alias cb='pbcopy'
alias cbp='pbpaste'
alias cbpwd='pwd | pbcopy'
# Pfad kopieren
cppath() { echo -n "$(pwd)/$1" | pbcopy; echo "Copied: $(pwd)/$1"; }
# Dateiinhalt kopieren
cpfile() { cat "$1" | pbcopy; echo "Copied contents of $1"; }
# JSON formatieren und kopieren
cbjson() { pbpaste | jq . | pbcopy; echo "JSON formatted"; }
# Clipboard-Inhalt anzeigen und in Datei speichern
cbsave() { pbpaste | tee "$1"; }
2 Dateien & Programme öffnen
2.1 open – Dateien und URLs öffnen
open öffnet Dateien, Verzeichnisse und URLs mit der Standardanwendung.
Dateien öffnen:
# Mit Standard-App öffnen
open dokument.pdf
open bild.png
open tabelle.xlsx
# Mehrere Dateien
open datei1.txt datei2.txt datei3.txt
# Alle Bilder im Ordner
open *.jpg
Verzeichnisse öffnen:
# Aktuelles Verzeichnis im Finder
open .
# Bestimmtes Verzeichnis
open ~/Documents
open /Applications
# Home-Verzeichnis
open ~
URLs öffnen:
# Webseite im Standard-Browser
open https://www.example.com
# E-Mail-Link
open mailto:max@example.com
# FTP
open ftp://ftp.example.com
# Mit Parametern
open "https://www.google.com/search?q=terminal+commands"
Spezielle URLs:
# Systemeinstellungen
open "x-apple.systempreferences:"
open "x-apple.systempreferences:com.apple.preference.security"
# App Store
open "macappstore://itunes.apple.com/app/id1234567890"
# Maps
open "maps://?q=Berlin"
# FaceTime
open "facetime://max@example.com"
2.2 open -a – Mit bestimmter App öffnen
# Mit spezifischer App öffnen
open -a "Visual Studio Code" datei.txt
open -a Safari https://example.com
open -a "Google Chrome" index.html
open -a Preview bild.png
open -a TextEdit dokument.txt
# App ohne Datei starten
open -a Finder
open -a Terminal
open -a "Activity Monitor"
# Kurzform für .app im Applications-Ordner
open -a Safari
Mit Bundle-ID:
# Über Bundle-Identifier
open -b com.apple.Safari https://example.com
open -b com.microsoft.VSCode datei.txt
open -b com.apple.TextEdit dokument.txt
# Bundle-ID einer App finden
osascript -e 'id of app "Safari"'
# com.apple.Safari
mdls -name kMDItemCFBundleIdentifier /Applications/Safari.app
Neue Instanz:
# Neue App-Instanz (zweites Fenster)
open -n -a Safari
# Versteckt starten
open -j -a "Some App"
# Im Hintergrund (nicht in Vordergrund bringen)
open -g datei.txt
2.3 open -R – Im Finder anzeigen
# Datei im Finder zeigen (Reveal)
open -R datei.txt
# Öffnet Finder mit selektierter Datei
open -R ~/Documents/wichtig.pdf
# Nützlich für Downloads
open -R ~/Downloads/installer.dmg
Weitere Optionen:
| Option | Beschreibung |
|---|---|
-a APP | Mit bestimmter App öffnen |
-b BUNDLE | Mit Bundle-ID öffnen |
-e | Mit TextEdit öffnen |
-t | Mit Standard-Texteditor öffnen |
-f | stdin als Datei öffnen |
-F | Frische App (ohne gespeicherten Zustand) |
-W | Warten bis App beendet |
-R | Im Finder anzeigen |
-n | Neue Instanz |
-g | Im Hintergrund |
-j | Versteckt starten |
-h | App verstecken wenn andere aktiv |
Praktische Beispiele:
# Code im Editor öffnen
open -a "Visual Studio Code" ~/projekte/app/
# Screenshot im Preview öffnen
screencapture -i /tmp/screenshot.png && open -a Preview /tmp/screenshot.png
# Befehlsausgabe im Editor öffnen
ls -la | open -f -a TextEdit
# Auf App-Ende warten
open -W dokument.pdf
echo "PDF wurde geschlossen"
# Quick Look (Vorschau)
qlmanage -p datei.pdf
3 Systemeinstellungen
3.1 defaults – Einstellungen lesen
defaults liest und schreibt macOS-Einstellungen (Property Lists).
Einstellungen lesen:
# Alle Einstellungen einer App
defaults read com.apple.finder
# Bestimmte Einstellung
defaults read com.apple.finder ShowPathbar
# Globale Einstellungen
defaults read NSGlobalDomain
# Bestimmte globale Einstellung
defaults read NSGlobalDomain AppleShowAllExtensions
Einstellungen suchen:
# Nach Schlüssel suchen
defaults read | grep -i "pathbar"
# Alle Domains auflisten
defaults domains | tr ',' '\n'
# Alle Einstellungen einer Domain durchsuchen
defaults read com.apple.dock | grep -i "size"
Typ einer Einstellung:
# Typ ermitteln
defaults read-type com.apple.finder ShowStatusBar
# Type is boolean
3.2 defaults write – Einstellungen ändern
Syntax:
defaults write DOMAIN KEY VALUE
defaults write DOMAIN KEY -TYPE VALUE
Typen:
| Typ | Flag | Beispiel |
|---|---|---|
| String | -string | "text" |
| Integer | -int | 42 |
| Float | -float | 3.14 |
| Boolean | -bool | true, false, YES, NO |
| Array | -array | item1 item2 |
| Dictionary | -dict | key1 value1 key2 value2 |
Beispiele:
# Boolean
defaults write com.apple.finder ShowPathbar -bool true
# Integer
defaults write com.apple.dock tilesize -int 48
# Float
defaults write NSGlobalDomain com.apple.mouse.scaling -float 2.5
# String
defaults write com.apple.screencapture location -string "~/Screenshots"
# Array
defaults write com.apple.dock persistent-apps -array
Nach Änderungen:
# Finder neu starten
killall Finder
# Dock neu starten
killall Dock
# SystemUIServer neu starten (Menüleiste)
killall SystemUIServer
3.3 Nützliche versteckte Einstellungen
Finder:
# Versteckte Dateien anzeigen
defaults write com.apple.finder AppleShowAllFiles -bool true
# Pfadleiste anzeigen
defaults write com.apple.finder ShowPathbar -bool true
# Statusleiste anzeigen
defaults write com.apple.finder ShowStatusBar -bool true
# Dateiendungen immer anzeigen
defaults write NSGlobalDomain AppleShowAllExtensions -bool true
# Warnung bei Endungsänderung deaktivieren
defaults write com.apple.finder FXEnableExtensionChangeWarning -bool false
# Standard-Ansicht (Liste)
defaults write com.apple.finder FXPreferredViewStyle -string "Nlsv"
# Nlsv=Liste, icnv=Icons, clmv=Spalten, Flwv=Cover Flow
# Neues Fenster zeigt Home
defaults write com.apple.finder NewWindowTarget -string "PfHm"
# Finder beenden erlauben
defaults write com.apple.finder QuitMenuItem -bool true
killall Finder
Dock:
# Dock-Größe
defaults write com.apple.dock tilesize -int 36
# Vergrößerung
defaults write com.apple.dock magnification -bool true
defaults write com.apple.dock largesize -int 64
# Position (left, bottom, right)
defaults write com.apple.dock orientation -string "left"
# Automatisch ausblenden
defaults write com.apple.dock autohide -bool true
# Ausblende-Verzögerung
defaults write com.apple.dock autohide-delay -float 0
defaults write com.apple.dock autohide-time-modifier -float 0.5
# Nur aktive Apps zeigen
defaults write com.apple.dock static-only -bool true
# Letzte Apps deaktivieren
defaults write com.apple.dock show-recents -bool false
# App-Indikatoren (Punkte) ausblenden
defaults write com.apple.dock show-process-indicators -bool false
# Spaces-Animation beschleunigen
defaults write com.apple.dock workspaces-edge-delay -float 0.1
killall Dock
Screenshots:
# Speicherort ändern
defaults write com.apple.screencapture location -string "~/Screenshots"
# Format ändern (png, jpg, gif, pdf, tiff)
defaults write com.apple.screencapture type -string "png"
# Schatten deaktivieren
defaults write com.apple.screencapture disable-shadow -bool true
# Dateiname-Präfix
defaults write com.apple.screencapture name -string "Screenshot"
# Zeitstempel im Namen deaktivieren
defaults write com.apple.screencapture include-date -bool false
killall SystemUIServer
Safari:
# Entwicklermenü aktivieren
defaults write com.apple.Safari IncludeDevelopMenu -bool true
# Web Inspector aktivieren
defaults write com.apple.Safari WebKitDeveloperExtrasEnabledPreferenceKey -bool true
# Vollständige URL anzeigen
defaults write com.apple.Safari ShowFullURLInSmartSearchField -bool true
# Links in Tabs öffnen
defaults write com.apple.Safari TargetedClicksCreateTabs -bool true
Tastatur & Eingabe:
# Tastenwiederholung (schneller)
defaults write NSGlobalDomain KeyRepeat -int 2
# Verzögerung bis Wiederholung
defaults write NSGlobalDomain InitialKeyRepeat -int 15
# Autokorrektur deaktivieren
defaults write NSGlobalDomain NSAutomaticSpellingCorrectionEnabled -bool false
# Automatische Großschreibung deaktivieren
defaults write NSGlobalDomain NSAutomaticCapitalizationEnabled -bool false
# Smart Quotes deaktivieren
defaults write NSGlobalDomain NSAutomaticQuoteSubstitutionEnabled -bool false
# Smart Dashes deaktivieren
defaults write NSGlobalDomain NSAutomaticDashSubstitutionEnabled -bool false
Verschiedenes:
# Crash-Reporter-Dialoge als Notification
defaults write com.apple.CrashReporter UseUNC 1
# Erweiterten Druckdialog als Standard
defaults write NSGlobalDomain PMPrintingExpandedStateForPrint -bool true
# Erweiterten Speicherdialog als Standard
defaults write NSGlobalDomain NSNavPanelExpandedStateForSaveMode -bool true
# .DS_Store auf Netzwerklaufwerken deaktivieren
defaults write com.apple.desktopservices DSDontWriteNetworkStores -bool true
# Bluetooth-Audio-Qualität (aptX)
defaults write com.apple.BluetoothAudioAgent "Apple Bitpool Min (editable)" -int 40
# Subpixel-Font-Rendering (für externe Monitore)
defaults write NSGlobalDomain AppleFontSmoothing -int 1
# App Nap deaktivieren (für alle Apps)
defaults write NSGlobalDomain NSAppSleepDisabled -bool true
Mission Control:
# Fenster nach App gruppieren
defaults write com.apple.dock expose-group-apps -bool true
# Spaces automatisch neu anordnen deaktivieren
defaults write com.apple.dock mru-spaces -bool false
# Dashboard deaktivieren
defaults write com.apple.dashboard mcx-disabled -bool true
killall Dock
3.4 defaults delete – Einstellungen zurücksetzen
# Einzelne Einstellung löschen
defaults delete com.apple.finder ShowPathbar
# Alle Einstellungen einer App zurücksetzen
defaults delete com.apple.finder
# Globale Einstellung löschen
defaults delete NSGlobalDomain AppleShowAllExtensions
# Nach Löschen: App neu starten
killall Finder
Aktuelle Einstellungen sichern:
# Domain exportieren
defaults export com.apple.finder ~/finder-backup.plist
# Domain importieren
defaults import com.apple.finder ~/finder-backup.plist
4 Automator & Shortcuts
4.1 Shell-Skripte in Automator
Automator kann Shell-Skripte ausführen und in Workflows integrieren.
Workflow erstellen:
- Automator öffnen
- Neues Dokument → Workflow oder Quick Action
- “Shell-Skript ausführen” aus der Bibliothek ziehen
- Shell wählen (
/bin/zsh) und Skript eingeben
Eingabe-Optionen:
| Option | Beschreibung |
|---|---|
| “an stdin” | Eingabe als stdin |
| “als Argumente” | Eingabe als $1, $2, … |
Beispiel: Bilder konvertieren
#!/bin/zsh
# Shell: /bin/zsh
# Eingabe: als Argumente
for f in "$@"; do
sips -s format png "$f" --out "${f%.*}.png"
done
Beispiel: Text transformieren
#!/bin/zsh
# Shell: /bin/zsh
# Eingabe: an stdin
tr '[:lower:]' '[:upper:]'
Beispiel: Clipboard verarbeiten
#!/bin/zsh
# Kein Input nötig
pbpaste | sort -u | pbcopy
osascript -e 'display notification "Duplikate entfernt" with title "Automator"'
4.2 Quick Actions erstellen
Quick Actions erscheinen im Finder-Kontextmenü und der Touch Bar.
Quick Action erstellen:
- Automator → Neues Dokument → “Schnellaktion”
- Eingabe: “Dateien oder Ordner” in “Finder”
- Shell-Skript hinzufügen
- Speichern (Name erscheint im Kontextmenü)
Beispiel: In Terminal öffnen
#!/bin/zsh
# Eingabe: als Argumente
for f in "$@"; do
if [-d "$f"](-d%20"$f".md); then
open -a Terminal "$f"
break
else
open -a Terminal "$(dirname "$f")"
break
fi
done
Beispiel: Bilder verkleinern
#!/bin/zsh
# Eingabe: als Argumente
for f in "$@"; do
sips --resampleWidth 1920 "$f" --out "${f%.*}_small.${f##*.}"
done
osascript -e 'display notification "Bilder verkleinert" with title "Quick Action"'
Beispiel: PDF zusammenfügen
#!/bin/zsh
# Eingabe: als Argumente
output="$HOME/Desktop/Merged_$(date +%Y%m%d_%H%M%S).pdf"
"/System/Library/Automator/Combine PDF Pages.action/Contents/MacOS/join" -o "$output" "$@"
open -R "$output"
Speicherort:
~/Library/Services/
4.3 Integration mit Shortcuts-App
Die Shortcuts-App (ab macOS Monterey) kann Shell-Skripte ausführen.
Shell-Skript in Shortcuts:
- Shortcuts-App öffnen
- Neuer Shortcut
- “Shell-Skript ausführen” hinzufügen
- Shell und Eingabe konfigurieren
Eingabe verwenden:
#!/bin/zsh
# "Shortcut-Eingabe" ist verfügbar als stdin oder $1
# Als stdin
cat | tr '[:lower:]' '[:upper:]'
# Als Argument
echo "$1" | tr '[:lower:]' '[:upper:]'
Shortcuts per Terminal ausführen:
# Shortcut ausführen
shortcuts run "Mein Shortcut"
# Mit Eingabe
echo "text" | shortcuts run "Mein Shortcut"
# Ergebnis erhalten
shortcuts run "Mein Shortcut" <<< "input"
# Shortcut-Liste
shortcuts list
Beispiel: API-Aufruf
#!/bin/zsh
curl -s "https://api.example.com/data" | jq -r '.result'
Beispiel: Systeminfo
#!/bin/zsh
echo "Hostname: $(hostname)"
echo "User: $(whoami)"
echo "Uptime: $(uptime | awk -F'up ' '{print $2}' | awk -F',' '{print $1}')"
echo "IP: $(ipconfig getifaddr en0)"
5 Weitere macOS-Befehle
5.1 say – Text vorlesen
say wandelt Text in Sprache um (Text-to-Speech).
Grundlegende Nutzung:
# Text vorlesen
say "Hallo Welt"
# Aus Datei vorlesen
say -f dokument.txt
# Von stdin
echo "Test" | say
# Clipboard vorlesen
pbpaste | say
Stimme wählen:
# Mit bestimmter Stimme
say -v Anna "Guten Tag" # Deutsch
say -v Samantha "Hello" # Englisch (US)
say -v Daniel "Hello" # Englisch (UK)
# Verfügbare Stimmen
say -v ?
# Alle deutschen Stimmen
say -v ? | grep de_
In Datei speichern:
# Als AIFF
say -o ausgabe.aiff "Dieser Text wird gespeichert"
# Als MP4/M4A
say -o ausgabe.m4a --data-format=aac "Dieser Text"
Geschwindigkeit:
# Langsamer (Standard: ~175 Wörter/Minute)
say -r 100 "Langsam gesprochen"
# Schneller
say -r 250 "Schnell gesprochen"
Interaktiv (Zeichen für Zeichen):
# Eingabe Zeichen für Zeichen vorlesen
say -i
Praktische Anwendungen:
# Nach langem Befehl benachrichtigen
make build && say "Build fertig" || say "Build fehlgeschlagen"
# Timer
sleep 300 && say "5 Minuten vorbei"
# Pomodoro
{ sleep 1500 && say "Pause machen"; sleep 300 && say "Weiterarbeiten"; } &
5.2 screencapture – Screenshots per Terminal
Bildschirmfoto:
# Ganzer Bildschirm
screencapture screenshot.png
# Interaktive Auswahl (wie Cmd+Shift+4)
screencapture -i screenshot.png
# Bestimmtes Fenster (wie Cmd+Shift+4, Space)
screencapture -iW screenshot.png
# Mit Mauszeiger
screencapture -C screenshot.png
# Ohne Schatten bei Fenstern
screencapture -o screenshot.png
In Zwischenablage:
# In Clipboard statt Datei
screencapture -c
# Interaktiv in Clipboard
screencapture -ic
Verzögerung:
# 5 Sekunden warten
screencapture -T 5 screenshot.png
# Interaktiv mit Verzögerung
screencapture -i -T 3 screenshot.png
Formate:
# PNG (Standard)
screencapture -t png screenshot.png
# JPEG
screencapture -t jpg screenshot.jpg
# PDF
screencapture -t pdf screenshot.pdf
# TIFF
screencapture -t tiff screenshot.tiff
Mehrere Bildschirme:
# Jeden Monitor separat
screencapture screen1.png screen2.png
# Nur bestimmten Monitor (-D)
screencapture -D 1 screen.png # Hauptmonitor
screencapture -D 2 screen.png # Zweiter Monitor
Optionen:
| Option | Beschreibung |
|---|---|
-i | Interaktive Auswahl |
-iW | Fenster-Auswahl |
-iU | Fenster ohne Schatten |
-c | In Zwischenablage |
-C | Mit Mauszeiger |
-o | Ohne Fensterschatten |
-T SEC | Verzögerung |
-t TYPE | Format (png, jpg, pdf) |
-x | Ohne Ton |
-D N | Display N |
-R x,y,w,h | Rechteck-Bereich |
Praktische Beispiele:
# Schneller Screenshot auf Desktop
screencapture -x ~/Desktop/screenshot-$(date +%Y%m%d-%H%M%S).png
# Bereich 800x600 ab Position 100,100
screencapture -R 100,100,800,600 region.png
# Screenshot-Funktion
screenshot() {
local name="${1:-screenshot}"
screencapture -i ~/Screenshots/"${name}_$(date +%Y%m%d_%H%M%S).png"
}
5.3 caffeinate – Ruhezustand verhindern
caffeinate verhindert, dass der Mac in den Ruhezustand geht.
Grundlegende Nutzung:
# Bis zum Abbruch (Ctrl+C)
caffeinate
# Für bestimmte Zeit (Sekunden)
caffeinate -t 3600 # 1 Stunde
# Während Befehl läuft
caffeinate -s make build
# Während Prozess läuft
caffeinate -w 1234 # PID 1234
Optionen:
| Option | Beschreibung |
|---|---|
-d | Display wach halten |
-i | System wach halten (idle) |
-m | Disk wach halten |
-s | System wach halten (auch mit Netzteil) |
-u | User aktiv simulieren |
-t SEC | Timeout in Sekunden |
-w PID | Bis Prozess endet |
Praktische Beispiele:
# Während langer Download
caffeinate -i wget https://example.com/large-file.zip
# Während Backup
caffeinate -im rsync -avz /source/ /backup/
# Präsentation: Display an lassen
caffeinate -d -t 7200 # 2 Stunden
# Bis bestimmter Prozess endet
caffeinate -w $(pgrep -x "Handbrake")
Als Hintergrundprozess:
# Im Hintergrund starten
caffeinate -d &
CAFFEINE_PID=$!
# Später beenden
kill $CAFFEINE_PID
5.4 mdfind – Spotlight-Suche per Terminal
mdfind nutzt den Spotlight-Index für schnelle Suchen.
Grundlegende Suche:
# Nach Name oder Inhalt
mdfind "projektplan"
# Nur Dateinamen
mdfind -name "readme.md"
# In bestimmtem Verzeichnis
mdfind -onlyin ~/Documents "bericht"
Nach Dateityp:
# PDFs
mdfind "kind:pdf projektplan"
# Bilder
mdfind "kind:image"
# E-Mails
mdfind "kind:email from:max"
# Präsentationen
mdfind "kind:presentation"
Metadata-Attribute:
# Nach Erstellungsdatum
mdfind "kMDItemContentCreationDate > \$time.today(-7)"
# Nach Autor
mdfind "kMDItemAuthors == 'Max Mustermann'"
# Nach Dateiendung
mdfind "kMDItemFSName == '*.py'"
# Nach Größe (Bytes)
mdfind "kMDItemFSSize > 100000000" # > 100 MB
Kombinierte Abfragen:
# PDF und Name
mdfind "kind:pdf AND name:report"
# In Ordner, bestimmter Typ
mdfind -onlyin ~/Projects "kind:source"
# Kürzlich geändert
mdfind "kMDItemContentModificationDate > \$time.today(-1)"
Live-Suche:
# Ergebnisse live aktualisieren
mdfind -live "projektplan"
Mit anderen Befehlen:
# Gefundene PDFs öffnen
mdfind -name "report.pdf" | head -1 | xargs open
# Ergebnisse zählen
mdfind "kind:image" -onlyin ~/Pictures | wc -l
# Größe aller gefundenen Dateien
mdfind "kind:movie" | xargs du -ch | tail -1
Spotlight-Index verwalten:
# Index-Status
mdutil -s /
# Index neu erstellen
sudo mdutil -E /
# Spotlight für Volume deaktivieren
sudo mdutil -i off /Volumes/USB
5.5 afplay – Audio abspielen
afplay spielt Audiodateien über das Terminal.
Grundlegende Nutzung:
# Datei abspielen
afplay musik.mp3
afplay sound.aiff
afplay audio.m4a
# System-Sounds abspielen
afplay /System/Library/Sounds/Ping.aiff
afplay /System/Library/Sounds/Glass.aiff
Optionen:
# Lautstärke (0.0 - 1.0)
afplay -v 0.5 musik.mp3
# Abspielrate (1.0 = normal)
afplay -r 1.5 musik.mp3 # 50% schneller
afplay -r 0.5 musik.mp3 # 50% langsamer
# Bestimmte Zeit abspielen
afplay -t 10 musik.mp3 # 10 Sekunden
# Im Hintergrund
afplay musik.mp3 &
System-Sounds:
# Verfügbare System-Sounds
ls /System/Library/Sounds/
# Notification-Sound
afplay /System/Library/Sounds/Funk.aiff
# Für Skript-Benachrichtigungen
notify() {
afplay /System/Library/Sounds/Glass.aiff
osascript -e "display notification \"$1\" with title \"Terminal\""
}
# Verwendung
make build && notify "Build fertig"
Praktische Beispiele:
# Wecker
sleep 3600 && afplay /System/Library/Sounds/Ping.aiff
# Befehl mit Sound bei Fertigstellung
long-running-command; afplay /System/Library/Sounds/Hero.aiff
# Alle MP3s in Ordner abspielen
for f in *.mp3; do afplay "$f"; done
# Zufälliger System-Sound
afplay /System/Library/Sounds/$(ls /System/Library/Sounds/ | sort -R | head -1)
Aliase:
# ~/.zshrc
# Benachrichtigungs-Sounds
alias beep='afplay /System/Library/Sounds/Ping.aiff'
alias done='afplay /System/Library/Sounds/Glass.aiff'
alias error='afplay /System/Library/Sounds/Basso.aiff'
# Nach langem Befehl
alias alert='afplay /System/Library/Sounds/Hero.aiff && osascript -e "display notification \"Fertig\" with title \"Terminal\""'
Weitere Audio-Befehle:
# Systemlautstärke
osascript -e "set volume output volume 50" # 0-100
osascript -e "output volume of (get volume settings)"
# Stummschalten
osascript -e "set volume output muted true"
osascript -e "set volume output muted false"
# Audio-Gerät Info
system_profiler SPAudioDataType
Python
python
| Befehl | Beschreibung |
|---|---|
python --version | Python-Version prüfen |
python -c "print('Hello')" | Python-Code direkt ausführen |
python script.py | Skript ausführen |
python -m module_name | Modul als Skript ausführen |
python -m venv .venv | Virtuelle Umgebung erstellen |
python -i script.py | Skript ausführen, danach interaktiv bleiben |
python -m http.server 8000 | Einfachen Webserver starten |
python -m json.tool file.json | JSON formatiert ausgeben |
conda
| Befehl | Beschreibung |
|---|---|
conda --version | Conda-Version prüfen |
conda env list | Umgebungen auflisten |
conda activate py310 | Umgebung aktivieren |
conda deactivate | Umgebung deaktivieren |
conda create -n py310 python=3.10 | Umgebung erstellen |
conda create --name py312 --clone py310 | Umgebung klonen |
conda remove -n py310 --all | Umgebung löschen |
conda install numpy | Paket installieren |
conda install python=3.12 | Python-Version aktualisieren |
conda update --all | Alle Pakete aktualisieren |
conda update conda | Conda selbst aktualisieren |
conda list | Installierte Pakete anzeigen |
conda search numpy | Nach Paketen suchen |
conda info | Conda-Informationen anzeigen |
conda clean --all | Cache und ungenutzte Pakete löschen |
conda env export > environment.yml | Umgebung exportieren |
conda env create -f environment.yml | Umgebung aus Datei erstellen |
pip
| Befehl | Beschreibung |
|---|---|
pip --version | pip-Version prüfen |
pip install package | Paket installieren |
pip install package==1.2.3 | Bestimmte Version installieren |
pip install -U package | Paket aktualisieren |
pip install -r requirements.txt | Alle Pakete aus Datei installieren |
pip uninstall package | Paket deinstallieren |
pip list | Installierte Pakete anzeigen |
pip list --outdated | Veraltete Pakete anzeigen |
pip show package | Paket-Informationen anzeigen |
pip search package | Nach Paketen suchen (oft deaktiviert) |
pip freeze > requirements.txt | Installierte Pakete exportieren |
pip cache purge | pip-Cache leeren |
pip install -e . | Paket im Entwicklungsmodus installieren |
pip install --user package | Nur für aktuellen Benutzer installieren |
Rust
rustup
| Befehl | Beschreibung |
|---|---|
rustup --version | rustup-Version prüfen |
rustup show | Installierte Toolchains anzeigen |
rustup update | Rust aktualisieren |
rustup default stable | Standard-Toolchain setzen |
rustup default nightly | Nightly als Standard setzen |
rustup toolchain list | Installierte Toolchains auflisten |
rustup toolchain install nightly | Nightly installieren |
rustup toolchain uninstall nightly | Toolchain entfernen |
rustup component add clippy | Komponente hinzufügen |
rustup component add rustfmt | Formatter hinzufügen |
rustup component list | Verfügbare Komponenten anzeigen |
rustup doc | Rust-Dokumentation öffnen |
rustup doc --std | Standardbibliothek-Doku öffnen |
rustup override set nightly | Toolchain für Projekt setzen |
rustup self update | rustup selbst aktualisieren |
cargo
Projekt erstellen & verwalten
| Befehl | Beschreibung |
|---|---|
cargo new project_name | Neues Projekt erstellen (mit Git) |
cargo new --lib library_name | Neue Bibliothek erstellen |
cargo init | Projekt im aktuellen Ordner initialisieren |
cargo init --lib | Bibliothek im aktuellen Ordner initialisieren |
Bauen & Ausführen
| Befehl | Beschreibung |
|---|---|
cargo build | Projekt kompilieren (Debug) |
cargo build --release | Release-Build erstellen |
cargo run | Kompilieren und ausführen |
cargo run --release | Release-Build ausführen |
cargo run -- arg1 arg2 | Mit Argumenten ausführen |
cargo run --bin binary_name | Bestimmte Binary ausführen |
cargo run --example example_name | Beispiel ausführen |
Testen & Prüfen
| Befehl | Beschreibung |
|---|---|
cargo test | Alle Tests ausführen |
cargo test test_name | Bestimmten Test ausführen |
cargo test --release | Tests im Release-Modus |
cargo test -- --nocapture | Ausgabe nicht unterdrücken |
cargo bench | Benchmarks ausführen |
cargo check | Kompilierbarkeit prüfen (schnell) |
Dependencies
| Befehl | Beschreibung |
|---|---|
cargo add package | Dependency hinzufügen |
cargo add package@1.2.3 | Bestimmte Version hinzufügen |
cargo add package --dev | Dev-Dependency hinzufügen |
cargo remove package | Dependency entfernen |
cargo update | Dependencies aktualisieren |
cargo tree | Dependency-Baum anzeigen |
cargo search package | Nach Crates suchen |
Code-Qualität
| Befehl | Beschreibung |
|---|---|
cargo fmt | Code formatieren |
cargo fmt --check | Formatierung prüfen |
cargo clippy | Linter ausführen |
cargo clippy --fix | Lint-Fehler automatisch beheben |
cargo fix | Compiler-Warnungen beheben |
Dokumentation & Infos
| Befehl | Beschreibung |
|---|---|
cargo doc | Dokumentation generieren |
cargo doc --open | Dokumentation generieren und öffnen |
cargo doc --no-deps | Ohne Dependencies dokumentieren |
Aufräumen & Sonstiges
| Befehl | Beschreibung |
|---|---|
cargo clean | Build-Artefakte löschen |
cargo publish | Crate auf crates.io veröffentlichen |
cargo install package | Binary global installieren |
cargo uninstall package | Binary deinstallieren |
make
| Befehl | Beschreibung |
|---|---|
make | Standard-Target ausführen (meist all) |
make target | Bestimmtes Target ausführen |
make -n target | Dry-run – zeigt was ausgeführt würde |
make -j4 | Parallel mit 4 Jobs bauen |
make -j$(nproc) | Parallel mit allen CPUs bauen |
make -f other.mk | Anderes Makefile verwenden |
make -B | Alles neu bauen (ignore timestamps) |
make clean | Aufräumen (falls Target definiert) |
make -p | Alle Variablen und Regeln anzeigen |
make VAR=value | Variable beim Aufruf setzen |
just
| Befehl | Beschreibung |
|---|---|
just | Standard-Rezept ausführen |
just recipe | Bestimmtes Rezept ausführen |
just -l / just --list | Alle Rezepte auflisten |
just --show recipe | Rezept-Definition anzeigen |
just -n recipe | Dry-run – zeigt was ausgeführt würde |
just --choose | Rezept interaktiv auswählen (mit fzf) |
just -f other.just | Anderes Justfile verwenden |
just --summary | Kurze Übersicht aller Rezepte |
just --evaluate | Alle Variablen ausgeben |
just recipe arg1 arg2 | Rezept mit Argumenten aufrufen |
just --init | Neues Justfile erstellen |
Beispiel justfile:
# Standard-Rezept
default:
@just --list
# Projekt bauen
build:
cargo build --release
# Tests ausführen
test:
cargo test
# Formatieren und linten
check:
cargo fmt --check
cargo clippy
# Aufräumen
clean:
cargo clean
tree
| Befehl | Beschreibung |
|---|---|
tree | Verzeichnisbaum anzeigen |
tree -L 2 | Nur 2 Ebenen tief |
tree -a | Auch versteckte Dateien anzeigen |
tree -d | Nur Verzeichnisse anzeigen |
tree -I "node_modules" | Ordner ausschließen |
tree -I "*.pyc" | Dateien nach Muster ausschließen |
tree -I "node_modules|.git|__pycache__" | Mehrere Muster ausschließen |
tree -P "*.py" | Nur bestimmte Dateien anzeigen |
tree -h | Dateigrößen anzeigen (human-readable) |
tree -s | Dateigrößen in Bytes anzeigen |
tree -D | Änderungsdatum anzeigen |
tree -p | Berechtigungen anzeigen |
tree -u | Besitzer anzeigen |
tree -f | Volle Pfade anzeigen |
tree -o output.txt | In Datei speichern |
tree --gitignore | .gitignore-Regeln beachten |
tree -C | Farbige Ausgabe (Standard im Terminal) |
tree -n | Keine Farben |
Terminals und Erweiterungen
Im folgenden werden neben dem Standard-Terminal weitere beliebte Terminal-Apps für macOS vorgestellt. Es wird kurz erklärt, was sie besonders machen und welche Vor- und Nachteile sie haben.
1 Begriffserklärungen
In diesem Abschnitt wird erklärt, was Terminals, Shells, Frameworks und Prompts sind und wie sie aufeinander aufbauen.
1.1 Terminal
Beschreibung:
Das Fensterprogramm, das du auf deinem Computer öffnest, um Textbefehle einzugeben. Ein Terminal ist die Benutzeroberfläche, die mit einer Shell kommuniziert.
Beispiele:
- Apple Terminal (Standard in macOS)
- iTerm2
- Warp
Aufgabe:
- Zeigt Eingaben, Ausgaben, Farben, Tabs usw.
- Es führt selbst keine Befehle aus, sondern reicht sie an die Shell weiter.
1.2 Shell
Beschreibung:
Die Kommandozeilen-Umgebung, die Befehle interpretiert und ausführt. Sie ist das eigentliche “Gehirn” hinter dem Terminal.
Beispiele:
- bash (ältere Standardshell)
- zsh (Standard auf macOS seit Catalina)
- fish (freundlich & modern)
- nushell (strukturiert & datenorientiert)
- PowerShell (Microsoft, aber auch für macOS/Linux verfügbar)
Aufgabe:
- Befehle entgegennehmen, interpretieren und ausführen
- Skripte schreiben, Variablen verwalten, Prozesse steuern
1.3 Framework
Beschreibung:
Ein Erweiterungssystem für eine Shell (meist für zsh), das Plugins, Themes und Konfigurationen organisiert. Es macht die Shell komfortabler, modularer und automatisierter.
Beispiele:
- Oh My Zsh (riesige Plugin-Sammlung für zsh)
- Prezto (leichtgewichtige, schnellere Alternative zu Oh My Zsh)
- Zinit, Zplug, Antigen, Znap (Plugin-Manager für zsh)
Aufgabe:
- Plugins laden (z. B. für Git, Docker, Syntax-Highlighting, Autocomplete)
- Themes aktivieren
- Die Shell beim Start konfigurieren
1.4 Prompt
Beschreibung:
Der visuelle Teil der Shell, d. h. der Zeile, die eingegeben wird. Ein Prompt zeigt z. B. Ordner, Git-Status, Uhrzeit, Exit-Code oder andere Informationen.
Beispiele:
- Starship (universeller, moderner Prompt für alle Shells)
- Powerlevel10k (extrem anpassbar, für zsh)
- Pure (minimalistisch)
- Spaceship (optisch sehr ansprechend, Git-Infos integriert)
Aufgabe:
- Das “Gesicht” der Shell
- Zeigt Informationen und Statusindikatoren in Echtzeit
1.5 Zusammenspiel von Terminal, Shell, Framework und Prompt
┌──────────────────────────────────────────┐
│ Terminal (z. B. iTerm2, Warp) │
│ → öffnet und zeigt die Shell │
│ │
│ ┌──────────────────────────────────────┐ │
│ │ Shell (z. B. zsh oder bash) │ │
│ │ → für Befehle aus │ │
│ │ │ │
│ │ ┌──────────────────────────────────┐ │ │
│ │ │ Framework (z. B. Oh My Zsh) │ │ │
│ │ │ → verwaltet Plugins und Themes │ │ │
│ │ │ │ │ │
│ │ │ ┌──────────────────────────────┐ │ │ │
│ │ │ │ Prompt (z. B. Starship) │ │ │ │
│ │ │ │ → Zeigt Info und Design │ │ │ │
│ │ │ └──────────────────────────────┘ │ │ │
│ │ └──────────────────────────────────┘ │ │
│ └──────────────────────────────────────┘ │
└──────────────────────────────────────────┘
| Ebene | Beispiele | Hauptfunktion | Läuft … | Wichtig für |
|---|---|---|---|---|
| Terminal | iTerm2, Warp | Darstellung, Tabs, Farben, UI | unabhängig | Benutzeroberfläche |
| Shell | zsh, bash | Befehlseingabe & Ausführung | im Terminal | Logik & Skripting |
| Framework | Oh My Zsh, Prezto | Plugin-Management & Themes | in der Shell | Komfort & Automatisierung |
| Prompt | Starship, Pure | Visuelles Erscheinungsbild & Status | im Framework oder direkt in Shell | Übersicht & Design |
note
Terminal zeigt → Shell führt aus → Framework organisiert → Prompt präsentiert
1.6 Beispiele für Kombinationen von Terminal, Shell, Framework und Prompt
| Nutzerprofil | Terminal | Shell | Framework | Prompt |
|---|---|---|---|---|
| macOS-Standardnutzer | Apple Terminal | zsh | – | Standard zsh Prompt |
| Entwickler & Power-User | iTerm2 / Warp | zsh | – / Oh My Zsh | – / Warp Built-in Prompt / Powerlevel10k |
| Cross-Plattform-Entwickler | Tabby | bash / fish | – | Starship |
| Minimalist / Performance-Enthusiast | Alacritty | zsh | Prezto / Znap | Starship |
| Team & KI-orientiert | Warp | zsh | Oh My Zsh | Warp Built-in Prompt oder Starship |
2 Terminals für macOS
2.1 Apple Terminal
Webseite, kein GitHub
Beschreibung:
Das vorinstallierte Terminal von macOS. Es ist schlicht, zuverlässig und tief ins System integriert.
Vorteile:
- Keine Installation erforderlich :luc_arrow_right: direkt einsatzbereit
- Sehr stabil und ressourcenschonend
- Vollständig kompatibel mit macOS (z. B. Shell-Integration, Sicherheit, Schriftarten)
Nachteile:
- Keine modernen Komfortfunktionen (Tabs, Split Views, Themes sind rudimentär)
- Wenig anpassbar ohne externe Tools
- Kein “modernes” UI oder interaktive Features
2.2 iTerm2
Beschreibung:
Ein extrem beliebter und mächtiger Terminal-Ersatz, der seit Jahren als Standard für Power-User gilt.
Vorteile:
- Tabs, Split Panes, Hotkeys und Profile
- Sehr anpassbar (Themes, Transparenz, Triggers, Status Bar)
- Mächtige Such- und Verlaufsfunktionen
- Unterstützung für Maus-Events und sogar Inline-Bilder
- Kostenlos und Open Source
Nachteile:
- Die vielen Funktionen und Optionen können anfangs überfordern
2.3 Warp
Beschreibung:
Ein modernes Terminal mit Rust-Backend und graphischer Shell-Erweiterung. Warp bietet Funktionen für Terminalarbeit mit KI, Autocomplete und Teamunterstützung.
Vorteile:
- Sehr modernes UI mit Markdown, Blöcken und Befehlshistorie
- KI-Autocomplete & Chat-Integration
- Kollaborations-Features (Team-Sharing von Commands, Workflows)
- Sehr hohe Leistung dank Rust
Nachteile:
- Proprietär (nicht Open Source)
- Cloud-Features erfordern Account
2.4 Alacritty
Beschreibung:
Minimalistisches, GPU-beschleunigtes Terminal, das auf maximale Performance und Einfachheit ausgelegt ist.
Vorteile:
- Extrem schnell (GPU-Rendering)
- Cross-Plattform und Open Source
- Konfiguration über YAML-Datei – einfach für Entwickler
Nachteile:
- Keine GUI-Einstellungen (alles per Config-Datei)
- Keine Tabs oder Splits nativ (nur über Multiplexer wie tmux)
- Weniger Komfortfunktionen
2.5 Kitty
Beschreibung:
Modernes, GPU-beschleunigtes Terminal mit Fokus auf Geschwindigkeit und Erweiterbarkeit.
Vorteile:
- Schnell, leicht und optisch modern
- Unterstützung für Tabs, Splits, Grafiken und Emojis
- Erweiterbar durch Python-Skripte
Nachteile:
- Komplexe Konfiguration
- Weniger benutzerfreundlich als andere Terminals
2.6 Hyper
Beschreibung:
Auf Electron basierendes Terminal mit Webtechnologien (HTML, CSS, JS).
Vorteile:
- Sehr anpassbar dank Plugins und Themes (JavaScript-basiert)
- Attraktives, modernes Design
- Ideal für Webentwickler, die JS beherrschen
Nachteile:
- Electron-basiert → höherer RAM-Verbrauch als native Terminals
- Teilweise instabil bei langen Sessions
- Weniger performant
2.7 Tabby
Beschreibung:
Mmoderner, plattformübergreifender Terminal-Emulator mit Fokus auf Benutzerfreundlichkeit, Design und Erweiterbarkeit. Geschrieben in TypeScript/Electron.
Vorteile:
- Sehr schönes, modernes UI
- Tabs, Splits, SSH-Manager, Serial Support
- Plugins und Themes (JS-basiert)
- Cross-Plattform (macOS, Linux, Windows)
Nachteile:
- Electron-basiert → höherer RAM-Verbrauch als native Terminals
- Nicht so schnell wie native Terminals (z. B. iTerm2 oder Alacritty)
- Weniger stabil bei extrem langen Sessions
2.8 Ghostty
Beschreibung:
Moderner Terminal-Emulator von Mitchell Hashimoto (HashiCorp-Gründer), geschrieben in Zig. Ghostty kombiniert hohe Performance durch GPU-Beschleunigung mit einer plattformnativen UI (Swift/AppKit auf macOS, GTK4 auf Linux).
Vorteile:
- Sehr schnell durch GPU-Rendering (Metal auf macOS, OpenGL auf Linux)
- Plattformnative UI – fühlt sich wie eine echte Mac-App an
- Exzellente Defaults – funktioniert ohne Konfiguration out-of-the-box
- Einfache Konfiguration über Key-Value-Paare in
~/.config/ghostty/config - Tabs, Splits, hunderte eingebaute Themes
- Unterstützt Kitty Graphics Protocol und Kitty Keyboard Protocol
- Nerd Fonts funktionieren direkt ohne Setup
- Open Source
Nachteile:
- Relativ neu (Version 1.0 Ende 2024)
- Kein Windows-Support (nur macOS und Linux)
- Weniger etabliert und dokumentiert als iTerm2
2.9 Vergleich
| Terminal | Open Source | Leistung | Anpass- barkeit | Ober- fläche | Moderne Features (KI, Blöcke, Teams) | Schwierig- keitsgrad |
|---|---|---|---|---|---|---|
| Apple Terminal | ✅ | 🟢 | 🔴 | Klassisch | 🔴 | 🟢 |
| iTerm2 | ✅ | 🟢 | 🟢🟢🟢 | Klassisch | 🔴 | 🟡 |
| Warp | ❌ | 🟢🟢 | 🟡 | Modern | 🟢🟢🟢 | 🟢 |
| Alacritty | ✅ | 🟢🟢🟢 | 🟡 | Modern | 🔴 | 🟡 |
| Kitty | ✅ | 🟢🟢 | 🟢 | Modern | 🔴 | 🟡 |
| Hyper | ✅ | 🟡 | 🟢🟢 | Modern | 🟡 | 🟢 |
| Tabby | ✅ | 🟡 | 🟢🟢 | Sehr Modern | 🟡 | 🟢 |
| Ghostty | ✅ | 🟢🟢🟢 | 🟡 | Modern/Nativ | 🟡 | 🟢 |
Zusammenfassung:
-
Apple Terminal (Webseite, kein GitHub) Standard-Terminal von macOS, stabil und einfach, aber ohne moderne Features.
-
iTerm2 (Webseite, GitHub) Sehr funktionsreich: Tabs, Splits, Triggers, Profile, Open Source.
-
Warp (Warp, GitHub) Rust-basiertes Terminal mit KI, Blöcken, Workflows und Team-Sharing.
-
Alacritty (Webseite, GitHub) GPU-beschleunigt, blitzschnell und minimalistisch, ideal mit tmux.
-
Kitty (Webseite, GitHub) Schnelles, GPU-basiertes Terminal mit Tabs, Splits und Python-Erweiterungen.
-
Hyper (Webseite, GitHub) Electron-Terminal mit Webtechnologien, sehr anpassbar durch Plugins.
-
Tabby (Webseite, GitHub) Electron-basiert, schönes Design, Plugins, Themes, SSH-/Serial-Manager.
-
Ghostty (Webseite, GitHub) Zig-basiert, GPU-beschleunigt, plattformnative UI, exzellente Defaults.
Nutzungsempfehlung nach Anwendungsfall:
| Anwendungsfall | Empfohlenes Terminal |
|---|---|
| Einsteiger & Minimalisten | Apple Terminal |
| Power-User & Entwickler | iTerm2 |
| Teamarbeit & KI-Unterstützung | Warp |
| Maxiamle Performance & Tiling | Alacritty oder Kitty |
| Web-/JS-Entwickler | Hyper oder Tabby |
| SSH & Multi-Session-Management | Tabby |
| Native macOS-Experience & Performance | Ghostty |
3 Shells für macOS
3.1 zsh (Z Shell)
Beschreibung:
Standard-Shell auf macOS seit Catalina (v. 10.15; 2019). Zsh ist mächtig, skriptfähig und stark erweiterbar.
Vorteile:
- Modern, interaktive Features (Tab-Completion, Globbing)
- Viele Plugins und Themes verfügbar (z. B. via Oh My Zsh)
- Kompatibel zu bash-Skripten
Nachteile:
- Einige ältere bash-Skripte erfordern Anpassungen
- Steile Lernkurve bei komplexen Konfigurationen
3.2 bash
Beschreibung:
Ältere Standardshell, sehr verbreitet und auf fast allen Unix-Systemen verfügbar.
Vorteile:
- Stabil und gut dokumentiert
- Große Community & viele Tutorials
- Skripting sehr zuverlässig
Nachteile:
- Weniger moderne Features als zsh oder fish
- Interaktive Nutzung weniger komfortabel
3.3 fish (Friendly Interactive Shell)
Beschreibung:
Benutzerfreundliche, moderne Shell, fokussiert auf einfache Nutzung und Autovervollständigung.
Vorteile:
- Auto-Suggestions & Syntax-Highlighting standardmäßig
- Einfach zu konfigurieren, keine Frameworks nötig
- Moderne Features out-of-the-box
Nachteile:
- Nicht 100 % POSIX-kompatibel → manche Skripte funktionieren nicht direkt
- Kleinere Community als zsh/bash
3.4 nushell
Beschreibung:
Datenorientierte Shell, die Tabellen und strukturierte Daten direkt verarbeiten kann.
Vorteile:
- Ideal für Workflows mit CSV, JSON, SQL-Daten
- Modernes CLI mit strukturierter Ausgabe
- Cross-Plattform
Nachteile:
- Neue Syntax → Umstieg für erfahrene bash/zsh-Nutzer aufwendig
- Weniger verbreitet, kleineres Ökosystem
3.5 PowerShell
Beschreibung:
Microsoft-Shell, ursprünglich für Windows, jetzt cross-platform. Fokus auf Skripterstellung und Automatisierung.
Vorteile:
- Mächtige Skriptmöglichkeiten, Object-Pipeline
- Plattformübergreifend (Windows, macOS, Linux)
- Große Community & Module verfügbar
Nachteile:
- Für macOS-Nutzer ungewohnt (anderer Syntaxstil)
- CLI-Optik weniger minimalistisch
3.6 Vergleich
| Shell | Open Source | Leistung | Interaktive Features | Skriptfähigkeit | Lernkurve |
|---|---|---|---|---|---|
| bash | ✅ | 🟢🟢🟢 | 🟡 | 🟢🟢🟢 | 🟡 |
| zsh | ✅ | 🟢🟢 | 🟢🟢 | 🟢🟢🟢 | 🟡 |
| fish | ✅ | 🟢🟢 | 🟢🟢🟢 | 🟢🟢 | 🟡 |
| nushell | ✅ | 🟢🟢 | 🟢🟢 | 🟢🟢 | 🟢 |
| PowerShell | ✅ | 🟢🟢 | 🟢🟢 | 🟢🟢🟢 | 🟢 |
Zusammenfasung:
-
zsh (Webseite, GitHub) Erweiterte Shell mit Autovervollständigung, Themes, Plugins; beliebt für interaktives Arbeiten und Anpassung.
-
bash (Webseite, GitHub) Klassische Unix-Shell, sehr verbreitet, ideal für Scripting und Automatisierung, stabil und universell einsetzbar.
-
fish (Webseite, GitHub) Benutzerfreundlich, moderne Features wie Autosuggestions und Syntax Highlighting, weniger skriptorientiert, einfach zu lernen.
-
nushell (Webseite, GitHub) Daten-orientierte Shell für strukturiertes Arbeiten mit Tabellen, JSON, CSV; modernes CLI-Konzept.
-
PowerShell (Webseite, GitHub) Microsoft-Shell, sehr mächtig für Systemadministration, plattformübergreifend, stark auf Objekte statt Text fokussiert.
Nutzungsempfehlung nach Anwendungsfall:
| Anwendungsfall | Empfohlene Shell |
|---|---|
| Skripting & Automatisierung | bash / PowerShell |
| Interaktive Nutzung & Auto-Vervollständigung | zsh / fish |
| Datenorientiertes Arbeiten (JSON, CSV) | nushell |
| Windows-spezifische Administration | PowerShell |
4 Frameworks
Shell-Frameworks erleichtern die Verwaltung von Plugins, Themes und Konfigurationen für zsh (und teilweise andere Shells).
4.1 Oh My Zsh
Beschreibung:
Bekanntestes zsh-Framework, enthält hunderte Plugins und Themes.
Vorteile:
- Einfach zu installieren und konfigurieren
- Riesiges Plugin-Ökosystem
- Große Community
Nachteile:
- Etwas langsamer beim Starten bei vielen Plugins
- Überladen für Minimalisten
4.2 Prezto
Beschreibung:
Leichtgewichtige Alternative zu Oh My Zsh, schneller und schlanker.
Vorteile:
- Schneller als Oh My Zsh
- Modularer Aufbau
- Viele nützliche Plugins
Nachteile:
- Weniger Themes als bei Oh My Zsh
- Kleinere Community als bei Oh My Zsh
4.3 Zinit
Beschreibung:
Zinit (früher zplugin) ist ein sehr flexibler und leistungsstarker Zsh-Plugin-Manager, der gezieltes Laden von Plugins, Snippets und Themes erlaubt. Unterstützt auch Turbo-Features wie Lazy-Loading und asynchrones Laden.
Vorteile:
- Extrem flexibel, unterstützt komplexe Konfigurationen
- Sehr schnell durch Lazy-Loading von Plugins
- Unterstützt Snippets, Hooks und parallele Updates
Nachteile:
- Hohe Einarbeitungszeit
- Komplexere Konfiguration kann unübersichtlich werden
4.4 Zplug
Beschreibung:
Zplug ist ein moderner Zsh-Plugin-Manager, der Plugin-Installation, Updates und Lazy-Loading vereinfacht. Plugins und Themes können zentral verwaltet werden.
Vorteile:
- Einfache Installation und Verwaltung von Plugins
- Unterstützt Lazy-Loading für Leistung
- Gute Community und aktive Weiterentwicklung
Nachteile:
- Weniger mächtig als Zinit bei komplexen Setups
- Dokumentation teilweise lückenhaft
4.5 Antigen
Beschreibung:
Antigen ist ein minimalistischer Zsh-Plugin-Manager, der von Oh My Zsh inspiriert ist. Er lädt Plugins und Themes auf einfache Weise und eignet sich besonders für Nutzer, die schnell starten wollen.
Vorteile:
- Schnell und einfach zu konfigurieren
- Unterstützt Oh-My-Zsh-, Prezto- und andere Plugins
- Leichtgewichtig
Nachteile:
- Weniger Funktionen im Vergleich zu Zinit oder Zplug
- Eher für einfache bis mittlere Konfigurationen geeignet
4.6 Znap
Beschreibung:
Znap ist ein moderner, minimalistischer Plugin-Manager für Zsh, der besonders auf Performance setzt. Plugins werden nur bei Bedarf geladen, Updates sind einfach und schnell.
Vorteile:
- Sehr schnell durch Lazy-Loading
- Einfaches Update-Management
- Minimalistische und saubere Konfiguration
Nachteile:
- Weniger bekannt, kleinere Community
- Weniger Features als Zinit für komplexe Setups
4.7 Vergleich
| Framework | Open Source | Setup-Aufwand | Plugin-Unterstützung | Theme-Unterstützung | Wartung / Stabilität | Lernkurve |
|---|---|---|---|---|---|---|
| Oh My Zsh | ✅ | 🟢 | 🟢🟢🟢 | 🟢🟢 | 🟢 | 🟡 |
| Prezto | ✅ | 🟢🟢 | 🟢🟢 | 🟢🟢 | 🟢🟢 | 🟡 |
| Zinit | ✅ | 🟡 | 🟢🟢🟢 | 🟢🟢 | 🟢🟢 | 🟢 |
| Zplug | ✅ | 🟢🟢 | 🟢🟢🟢 | 🟢🟢 | 🟢🟢 | 🟢 |
| Antigen | ✅ | 🟡 | 🟢🟢🟢 | 🟢🟢 | 🟢🟢 | 🟢 |
| Znap | ✅ | 🟢 | 🟢🟢🟢 | 🟢 | 🟢🟢 | 🟢 |
Zusammenfassung:
-
Oh My Zsh (Webseite, GitHub) Einsteigerfreundliches Framework für zsh, viele Plugins und Themes, einfache Installation, weit verbreitet.
-
Prezto (GitHub) Schlankes, performantes zsh-Framework, schneller als Oh My Zsh, stabil, viele nützliche Defaults und Optimierungen.
-
Zinit (GitHub) Extrem anpassbar, leistungsstarker Plugin-Manager für zsh, viele Optimierungen möglich, für Power-User.
-
Zplug (GitHub) Moderne Alternative zu Antigen/Zinit, Plugin-Management und Themes für zsh, leichtgewichtig, erweiterbar.
-
Antigen (GitHub) Plugin-Manager für zsh, hohe Flexibilität, unterstützt Themes, viele Plugins, gut für fortgeschrittene Nutzer.
-
Znap (GitHub) Minimalistischer, performanter Zsh-Plugin-Manager, der Plugins nur bei Bedarf lädt, schnelle Updates, einfache Konfiguration für fortgeschrittene Nutzer.
Nutzungsempfehlung nach Anwendungsfall:
| Anwendungsfall | Empfohlenes Framework |
|---|---|
| Einsteiger, schnelle Installation | Oh My Zsh |
| Schlank & performant | Prezto |
| Viele Plugins & Themes | Antigen / Zinit / Zplug |
| Power-User, maximale Anpassbarkeit | Zinit / Zplug |
5 Prompts
Prompts sind die sichtbaren Eingabezeilen in der Shell, oft mit Statusinformationen, Farben und Symbolen.
5.1 Starship
Beschreibung:
Universeller Prompt für alle Shells, modern, schnell und anpassbar.
Vorteile:
- Cross-Shell & Cross-Platform
- Sehr anpassbar mit einfacher Konfigurationsdatei
- Schnelle Performance
Nachteile:
- Manche Features müssen manuell konfiguriert werden
- Für komplette Anpassung Kenntnisse von TOML nötig
5.2 Powerlevel10k
Beschreibung:
Extrem anpassbarer Prompt für zsh, bekannt für Performance und Optik.
Vorteile:
- Interaktives Setup, sehr individuell
- Git-Status, Icons, Farben, Unicode-Zeichen
- Schnell trotz umfangreicher Features
Nachteile:
- Nur für zsh
- Einarbeitung nötig, wenn viele Features aktiviert werden
5.3 Pure
Beschreibung:
Minimalistischer, sauberer Prompt für zsh und bash.
Vorteile:
- Minimalistisch & schnell
- Fokus auf Klarheit
- Zeigt Git-Status, aber keine unnötigen Extras
Nachteile:
- Weniger visuelle Features
- Kaum Anpassungsmöglichkeiten
5.4 Spaceship
Beschreibung:
Optisch ansprechender zsh-Prompt, zeigt Git-Info, Node-Version, Docker-Status uvm.
Vorteile:
- Viele Funktionen direkt integriert
- Optisch sehr ansprechendes Design
- Open Source
Nachteile:
- Nur für zsh
- Kann bei umfangreichen Infos den Start verzögern
5.5 Vergleich
| Prompt | Open Source | Geschwindigkeit | Anpassbarkeit | Shell-Kompatibilität | Featureumfang | Lernkurve |
|---|---|---|---|---|---|---|
| Starship | ✅ | 🟢🟢🟢 | 🟢🟢🟢 | Alle gängigen | 🟢🟢🟢 | 🟡 |
| Powerlevel10k | ✅ | 🟢🟢🟢 | 🟢🟢🟢 | zsh | 🟢🟢🟢 | 🟢 |
| Pure | ✅ | 🟢🟢🟢 | 🟢 | zsh | 🟢 | 🟡 |
| Spaceship | ✅ | 🟢🟢 | 🟢🟢 | zsh | 🟢🟢🟢 | 🟡🟢 |
Zusammenfassung:
-
Starship (Webseite, GitHub) Cross-Shell Prompt, modern, schnell, sehr anpassbar, zeigt Git-Status, Systeminfo und weitere Features.
-
Powerlevel10k (GitHub) Hochgradig anpassbarer zsh-Prompt, sehr performant, attraktive Optik, Git-Integration, beliebt bei Power-Usern.
-
Pure (GitHub) Minimalistischer zsh-Prompt, schnell, schlicht, zeigt Git-Status, ideal für Nutzer, die wenig Schnickschnack wollen.
-
Spaceship (GitHub) Funktionsreicher zsh-Prompt, viele Module und Themes, Git-Integration, modern und optisch ansprechend.
Nutzungsempfehlung nach Anwendungsfall:
| Anwendungsfall | Empfohlener Prompt |
|---|---|
| Cross-Shell, moderne Features | Starship |
| Git-Status & maximale Optik (zsh) | Powerlevel10k |
| Minimalistisch & schnell | Pure |
| Viele Features & ansprechendes Design | Spaceship |
6 Installation von Oh My Zsh und Starship
6.1 Oh My Zsh
Installation:
sh -c "$(curl -fsSL https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/master/tools/install.sh)"
note
Durch die Installation wird die Datei ~/.zshrc überschrieben! Zuvor wird jedoch ein Backup als ~/.zshrc.pre-oh-my-zsh erstellt. Alle benutzerdefinierten Inhalte (Aliase, Funktionen, usw.) müssen manuell in die neue Datei kopiert werden.
Anpassung:
Über Konfigurationsdatei:
~/.zshrc
Deinstallation:
Mit dem folgenden Befehl wird Oh My Zsh gelöscht und die Einstellungen vom Zeitpunkt vor der Installation (:luc_arrow_right: ursprüngliche ~/.zshrc) werden wieder hergestellt:
uninstall_oh_my_zsh
Sie auch: Uninstalling Oh My Zsh.
6.1.1 Plugins für Oh My Zsh
Vollständige Liste aller Plugins:
https://github.com/ohmyzsh/ohmyzsh/wiki/plugins
Besonders praktische Plugins:
-
zsh-autosuggestions, zsh-syntax-highlighting, zsh-fast-syntax-highlighting und zsh-autocomplete.md Verbessert die Effizienz beim Tippen im Terminal:
- zsh-autosuggestions schlägt automatisch vorherige Befehle vor
- zsh-syntax-highlighting und zsh-fast-syntax-highlighting heben die Eingabe farblich hervor
- zsh-autocomplete ergänzt Befehle und Dateinamen in Echtzeit
git clone https://github.com/zsh-users/zsh-autosuggestions.git $ZSH_CUSTOM/plugins/zsh-autosuggestions
git clone https://github.com/zsh-users/zsh-syntax-highlighting.git $ZSH_CUSTOM/plugins/zsh-syntax-highlighting
git clone https://github.com/zdharma-continuum/fast-syntax-highlighting.git ${ZSH_CUSTOM:-$HOME/.oh-my-zsh/custom}/plugins/fast-syntax-highlighting
git clone --depth 1 -- https://github.com/marlonrichert/zsh-autocomplete.git $ZSH_CUSTOM/plugins/zsh-autocomplete
-
sudo Schreibt
sudovor den aktuellen und vorherigen Befehl durch zweimalige Drücken derESC-Taste. -
web-search Starte eine Websuche vom Terminal aus, z. B. mit dem Befehl
google. -
copyfile Kopiert den Inhalt einer Datei in die Zwischenablage.
-
copybuffer Mit
STRG+Owird der aktuelle Text/Befehl in die Zwischenablage kopiert. -
dirhistory Es werden Tastaturkurzbefehle hinzugefügt um durch Ordner zu navigieren.
-
jsontools Leserliche Darstellung von JSON-Daten.
6.2 Starship
Installation:
brew install starship
Anpassung:
Über Konfigurationsdatei:
~/.config/starship.toml
Eine Erklärung, wie sich die aktuelle Prompt zusammensetzt liefert der folgende Befehl:
starship explain

Deinstallation:
brew uninstall starship
Siehe auch: How do I uninstall Starship?
tip
Für maximale Anpassungsmöglichkeiten empiehlt sich die Verwendung einer Nerd Font, welche zusätzliche Symbole liefert.
Beliebte Programme für die Kommandozeile
| Programm | Beschreibung |
|---|---|
| bat | Wie cat, aber mit zusätzlichen Funktionen wie Syntaxhighlighting und Git-Integration |
| bc | Kommandozeilen-Taschenrechner für mathematische Ausdrücke |
| claude-code | Nutzung von Claude-AI-Modellen, besonders für Programmier- und Analyse-Workflows |
| fzf | Fuzzy-Finder für die Kommandozeile – interaktives Suchen in Dateien, Verzeichnissen, Git-History usw. |
| gitui | Terminal-UI für Git – intuitive, schnelle grafische Bedienung von Git-Workflows direkt im Terminal |
| helix | Moderne modale Texteditor-Alternative zu Vim/NeoVim mit LSP-Integration und innovativem Bedienkonzept |
| htop | Interaktiver Prozess- und Ressourcenmonitor, erweiterte Version von top |
| mc | Midnight Commander: Dateimanager im Terminal in Anlehnung an Norton Commander (Total Commander für die Kommandozeile) |
| lsd | Wie ls, aber mit Farben, Icons, Baumansicht, besserem Format und erweiterten Optionen |
| micro | Benutzerfreundlicher Terminal-Texteditor mit Kurzbefehlen wie STRG+C, STRG+V, usw.; Alternative zu nano |
| neovim | Erweiterter, moderner Vim-Fork mit Plugin-System, LSP und besserer Integration in moderne Entwicklungs-Workflows |
| nnn | Extrem schneller, minimalistischer Dateimanager mit Plugin-System und vielen Integrationen |
| pandoc | Universeller Dokumenten-Konverter – wandelt praktisch jedes Format in jedes andere um |
| rsync | Leistungsstarkes Tool für Dateisynchronisation und Backups, unterstützt Delta-Übertragung und SSH |
| tldr | Vereinfachte, praxisorientierte Hilfeseiten mit Beispielen – schnelle Alternative zu man-Pages |
| tree | Zeigt Verzeichnisstrukturen im Baumformat an – übersichtliche Alternative zu rekursivem ls. |
Weitere Links zu Midnight Commander:
- midnight-commander.org
- GNU Midnight Commander Manual
- Midnight Commander Skin Editor
- Midnight Commander Keyboard Shortcuts by brechtm
- Midnight Commander Keyboard Shortcuts for macOS
- Midnight Commander Keyboard Shortcuts for Mac OSX
tip
Weitere Programme für das Terminal:
- Ausführliche und kategorisierte Liste weiterer Programme für die Kommandozeile: GitHub: awesome-macos-commandline
- Sammlung von CLI-Tools: https://terminaltrove.com
Gemeinsamkeiten mit Linux-Terminals
Vieles von dem, was für macOS-Terminals gelten, ist direkt auf Linux übertragbar, es gibt jedoch einige wichtige Unterschiede. In diesem Kapitel erfolgt eine genauere Betrachtung.
1 Shell
- macOS: Standardmäßig nutzt macOS seit macOS Catalina zsh (vorher war es bash).
- Linux: Die häufigste Shell ist bash, aber auch zsh, fish oder andere Shells sind möglich.
Bedeutung:
- Grundlegende Befehle (
ls,cd,cp,mv,mkdir,rm,cat,grep, usw.) funktionieren auf beiden Systemen gleich. - Skripte in
bashfunktionieren oft auch inzsh, aber manchezsh-spezifischen Features gibt es auf Linux nicht.
2 Dateisystem
-
macOS: HFS+ oder APFS. Pfade beginnen mit
/wie bei Linux, aber es gibt kleine Unterschiede:- macOS ist standardmäßig case-insensitive, d. h.
file.txt = File.txt. - macOS hat viele macOS-spezifische Verzeichnisse wie
/Applicationsoder/System.
- macOS ist standardmäßig case-insensitive, d. h.
-
Linux: Typisch ist ext4, XFS usw. Linux ist case-sensitive, d. h.
file.txt != File.txt.
3 Paketverwaltung
- macOS: Homebrew (
brew) ist die gängigste Lösung. - Linux: Abhängig von Distribution:
- Debian/Ubuntu → apt (
apt-get) - Fedora →
dnf - Arch →
pacman
- Debian/Ubuntu → apt (
Bedeutung: Viele Tools, die man mit brew install toolname installiert, haben auf Linux andere Paketnamen oder Befehle.
4 Systembefehle / Administratorrechte
- macOS:
sudofunktioniert wie auf Linux. Systemkonfigurationen laufen oft über grafische Apps oder/etc. - Linux:
sudooder direkt alsroot(su) üblich. Systemdienste verwaltest man meistens mitsystemctl.
5 Texteditoren
Sowohl macOS als auch Linux haben nano, vim und emacs. Unterschiede gibt es höchstens bei vorinstallierten Versionen.
6 Fazit
Wenn man das macOS-Terminal gut beherrscht:
- Alltägliche Navigation, Dateimanipulation, Skripting, Textbearbeitung, Pipes und Redirects sind sehr ähnlich.
- Systemverwaltung, Paketverwaltung, manche Pfade und systemnahe Befehle unterscheiden sich und müssen gelernt werden.
Die meisten Terminal-Befehle sind identisch, nur Systemdetails und Paketverwaltung unterscheiden sich.
| Kategorie | Befehl / Aufgabe | macOS Terminal | Linux Terminal | Hinweis | |
|---|---|---|---|---|---|
| Navigation | Aktuelles Verzeichnis | pwd | pwd | identisch | |
| Verzeichnis wechseln | cd /Pfad | cd /Pfad | identisch | ||
| Inhalt anzeigen | ls | ls | identisch; Optionen wie ls -l gleich | ||
| Verzeichnis erstellen | mkdir name | mkdir name | identisch | ||
| Dateien kopieren | cp quelle ziel | cp quelle ziel | identisch | ||
| Dateien verschieben/umbenennen | mv quelle ziel | mv quelle ziel | identisch | ||
| Datei löschen | rm datei | rm datei | identisch; Vorsicht bei rm -rf | ||
| Text und Suche | Datei anzeigen | cat datei | cat datei | identisch | |
| Zeilen durchsuchen | grep "text" datei | grep "text" datei | identisch | ||
| Texteditor | nano datei, vim datei | nano datei, vim datei | identisch, oft schon vorinstalliert | ||
| System & Info | Benutzer | whoami | whoami | identisch | |
| Systeminfo | uname -a | uname -a | identisch | ||
| Speicherplatz | df -h | df -h | identisch | ||
| Prozesse anzeigen | top | top oder htop | htop evtl. separat installieren | ||
| Rechte & Administration | Als Admin ausführen | sudo befehl | sudo befehl | identisch | |
| Root werden | sudo -i | sudo -i oder su - | kleine Unterschiede | ||
| Systemdienste | launchctl | systemctl | unterschiedlich, Linux nutzt meist systemctl | ||
| Paketverwaltung | Software installieren | brew install paket | sudo apt install paket | Paketnamen unterscheiden sich oft | |
| Software suchen | brew search paket | apt search paket | gleiches Prinzip, andere Befehle | ||
| Shell / Skripte | Shell starten | zsh | bash (häufig), zsh | Skripte meist kompatibel, zsh-spezifische Features evtl. anders | |
| Netzwerk | IP-Adresse anzeigen | ifconfig | ip addr | Linux nutzt moderne ip-Befehle häufiger | |
| Netzwerk testen | ping host | ping host | identisch | ||