Modul 13 — Capstone: ein echtes CLI-Projekt
CLI-Grundlagen: argv, Usage, Exit
Ein Kommandozeilen-Tool liest seine Eingaben aus Argumenten, verarbeitet
sie und beendet sich mit einem Exit-Code. env::args() ist der Eingang:
use std::env;
fn main() {
let argv: Vec<_> = env::args().collect();
match argv.get(1) {
Some(name) => println!("Guten Tag, {name}!"),
None => println!("Usage: guten-tag <name>"),
}
}
Drei Entscheidungen stecken in diesem Beispiel:
- argv.get(1) statt argv[1] — der Index-Zugriff paniziert ohne Argument;
getliefert eine Option, und der None-Zweig IST die Usage-Ausgabe - Usage statt Schweigen — ohne Eingabe zeigt das Tool, was es erwartet
- Kein panic im Hauptpfad — ein CLI, das bei falscher Eingabe crasht, ist kein Tool, sondern eine Bombe
Später lernst du process::exit(code) kennen — aber erst, wenn du die
Fehlermeldung nach stderr gedruckt hast, damit der Erfolgs-Pfad stdout
nicht verschmutzt.
Die CLI-Grundschrift
- argv[0] = Programmname; Eingaben beginnen bei Index 1
- get() statt Index-Zugriff: keine Panics bei fehlenden Argumenten
- Eine Usage-Zeile bei falscher oder fehlender Eingabe
- Fehlertext nach stderr (eprintln!), Ergebnis nach stdout
📝 Schnellprüfung
Warum argv.get(1) statt argv[1] für den Namen?
Übung: Argumente parsen
🧩 Übung m13-l1-e1
🔮 Vorhersage: Was passiert beim Ausführen?
✅ Wichtige Erkenntnisse
Haken setzen, um deinen Lernfortschritt zu markieren:
Dateien: laden, bearbeiten, speichern
Ein CLI ohne Dateien ist selten nützlich. fs::read_to_string holt eine
ganze Datei als String in den Speicher — und gibt dir das Ergebnis als
Result, denn Dateizugriff kann scheitern:
use std::env;
use std::fs;
fn main() {
let argv: Vec<_> = env::args().collect();
let pfad = argv.get(1).map(String::as_str).unwrap_or("notizen.txt");
match fs::read_to_string(pfad) {
Ok(inhalt) => println!("Zeilen: {}", inhalt.lines().count()),
Err(fehler) => eprintln!("Konnte '{pfad}' nicht lesen: {fehler}"),
}
}
Beachte die drei Bausteine, die Modul 7 ins Spiel bringt:
read_to_stringliefert Result — der Fehler darf nicht unter den Teppichunwrap_orgibt einen Standard-Pfad ohne Panic auseprintlnschreibt die Fehlermeldung nach stderr — stdout bleibt für echte Ergebnisse reserviert, damit Pipe-Partner sauber arbeiten
Und weil ein CLI-Nutzer nie dein unpackendes Innere sehen will: Fehler werden zu Meldungen, nicht zu Panics. Das ist die Anwendung von Error Handling auf die echte Welt.
Datei-Ein/Ausgabe ohne Stolperfallen
- fs::read_to_string pfad -> Result; match drauf, nie unwrap im Hauptpfad
- unwrap_or für Defaults statt einer Panik bei leeren Argumenten
- eprintln für Fehler, println für Ergebnisse — Trennung für Pipes
- .lines() leiht vom String — keine Kopie, saubere Iteration
📝 Schnellprüfung
Was sagt eprintln gegenüber println für einen Fehlerfall aus?
Übung: Datei laden ohne Panik
🧩 Übung m13-l2-e1
🔮 Vorhersage: Was passiert beim Ausführen?
✅ Wichtige Erkenntnisse
Haken setzen, um deinen Lernfortschritt zu markieren:
Verarbeiten: filtern, sortieren, suchen
Jetzt wird der geladene Text zur Auswertung. Alles, was du in Modul 10 gelernt hast, trifft hier auf die Daten einer Datei:
fn main() {
let log = "info start\nerror disk voll\ninfo retry\nerror timeout\n";
let such = "error";
let mut treffer: Vec<&str> = log
.lines()
.filter(|z| z.contains(such))
.collect();
treffer.sort();
for zeile in treffer {
println!("{zeile}");
}
}
Drei Fähigkeiten bisher, eine dritte dazu:
- lines() leiht Zeilen aus dem String — kein Kopieren, Modul 13 L2
- filter + collect bauen die Pipeline — Modul 10
- sort() — und hier verlangt das Sortieren einen kurzen Halt: Die Iterator-Kette reicht NICHT; du brauchst eine echte Vec, weil sortieren einen wahlfreien Zugriff auf die Elemente braucht
Die gesammelten Zeilen sind geliehene Slices aus dem String — sie leben
so lange wie der String. Da treffer im selben Scope bleibt, ist das
sicher und der Borrow-Checker nickt.
Für ein echtes Tool wird daraus eine Suche: suche:server zeigt nur
Zeilen mit "server". Die Funktion suche aus den Modul-Codes macht genau
das — filter, collect, fertig.
Datenfluss im CLI
- lines() leiht; die Vec geliehener Zeilen lebt mit dem String
- zum Sortieren brauchst du eine geordnete Sammlung, keine Iterator
- filter wählt Mengen aus, sort ordnet sie, collect bündelt beides
- Liste der Treffer: Teilmengen-Auswahl und Ordnung in wenigen Zeilen
📝 Schnellprüfung
Warum reicht eine Iterator-Kette zum Sortieren nicht aus?
Übung: Suchen & Sortieren
🧩 Übung m13-l3-e1
🔮 Vorhersage: Was passiert beim Ausführen?
✅ Wichtige Erkenntnisse
Haken setzen, um deinen Lernfortschritt zu markieren:
Das fertige Projekt & der Ausblick
Ein CLI lebt von klarer Struktur. Die bewährte Einteilung:
- Parsen — Argumente zu Befehlen machen (Modul 13 L1)
- Verarbeiten — Befehle auf den Zustand anwenden (Modul 13 L3)
- Ausgeben — das Ergebnis rendern (stdout)
Im Code des Capstones heißt das: parse_befehl übersetzt ein Argument
in einen Befehl der Todo-Welt — neu:TEXT hängt an, zeige zeigt alle,
suche:TEXT filtert. Der Zustand ist eine Vec von Notizen; jede Zeile
wird über eine Funktion gerendert, die einen Haken setzt oder nicht.
Warum diese Dreiteilung? Testbarkeit. Jede Stufe ist eine reine Funktion: Argumente rein, Befehle raus — Befehle rein, Zustand raus — Zustand rein, Text raus. Du kannst sie einzeln testen, ohne je ein Programm zu starten. Genau das macht die Übung deutlich.
🏢 Praxis-Szenario: Das Todo-Tool, das niemand mehr crashen sieht
Dein Team pflegt einen Notizzettel in einer Textdatei. Drei Kollegen haben eigene Mini-Skripte geschrieben — jedes crasht anders: der eine mit panic bei fehlender Datei, der andere gibt Fehler in die Ausgabepipeline aus, der dritte sortiert nie. Die Anforderung ist die eigene Lebensqualität: EIN Tool, das Argumente versteht, Dateien lädt, filtert und sortiert — ohne je zu explodieren.
🧩 Übung m13-l4-e1
🔮 Vorhersage: Was passiert beim Ausführen?
Was du aus dem Kurs mitnimmst
- Ownership, Borrowing und Lifetimes als Fundament — du weisst JETZT, warum Regeln existieren
- Fehler sind Werte: Result, ?, eigene Fehlertypen statt Panics
- Daten fliessen als Pipelines: Iteratoren, Option, keiner Zwischen-Kopie
- Teamwork: Threads, Channels, Mutex — und wann man sie nicht braucht
- Ein komplettes CLI-Projekt: strukturiert, testbar, ohne Wegwerf-Code
✅ Wichtige Erkenntnisse
Haken setzen, um deinen Lernfortschritt zu markieren:
Modul-Checkpoint
Checkpoint: Modul 13
Bestehensgrenze: 80 %. Der Versuch wird bewertet und zählt für das Modul-Gate.
Bereit, dein Wissen zu testen?
Probiere unsere Übungsprüfungen mit Hunderten von realistischen Fragen aus.
Üben starten →