#format rst :title: Shell II: die kleinen Helferlein :author: Dario & Lars :css: https://wiki.hack-hro.de/talk_styles/assets/css/style2.css :description: Hackspace Rostock e.V. :data-scale: 0.7 :data-transition-duration: 1 ---- :: ________ ________ / ______ \ / ______ \ / / \ \ / / \ \ / / \ " / \ \ | | \ / | | | | ____ _ " _ _ | | | | / ___|| |__ ___| | | | | | | \___ \| '_ \ / _ \ | | | | | | ___) | | | | __/ | | | | | | |____/|_| |_|\___|_|_| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | ---- Shell Workshop II ================= Ein Hoch auf die kleinen Helferlein! ---- Gestern, heute, morgen ---------------------- * Rückblick (letzter Workshop): Shell steuert Prozesse, Eingaben, Ausgaben ... * heute: kleine Programme, deren Funktionalitäten sich mit der Shell verknüpfen lassen * Abschluss (nächster Workshop): Shell-Skripte - sauber und robust (inkl. Substitution & Quoting) ---- Fahrplan -------- * reguläre Ausdrücke (kleiner Exkurs) * grep * sed * awk * coreutils & Co. ---- Seid bereit! ------------ * Startet eure Rechner * Besucht http://pad.hack-hro.de/Shell2-Spass * später werdet ihr es brauchen ... ---- Reguläre Ausdrücke ================== * reguläre Ausdrücke != globbing * Implementierungen sind leicht verschieden * Meta-Characters ---- Reguläre Ausdrücke - Beispiele ============================== ^foo ba[rz] hello (world|earth)! ---- grep ==== * Suche ein Muster in Textzeilen * Anwendungen: * Filterung * Prüfung * Dateisuche ---- grep - Beispiele ================ [\t ]state DOWN[\ ] ^[0-9]+(\.[0-9]+){3}(/[0-9]+)?$ [[:space:]]IN[[:space:]]\+SRV[[:space:]]\+[[:digit:]]\+[[:space:]]\+[[:digit:]] ---- sed === * sed => 'stream editor' * von '73 bis '74 von Lee E. McMahon in den Bell Labs entwickelt * Nachfolger des '71 entwickelten, interaktiven Editors ed * eines der frühesten Werkzeuge, das reguläre Ausdrücke interpretieren konnte * arbeitet auf 'per Zeilen'-Basis ---- Haben wir auch das wichtigste nicht vergessen? ============================================== .. code:: shell-session sed -n -e '/main[[:space:]]*(/,/^}/p' quelldatei.c | more ---- Grundlegende Kommandos (unvollständig) ====================================== * a - (append) fügt eine oder mehrere Zeilen an die passende Zeile an * c - (change) ersetzt die ausgewählte Zeile durch eine (oder mehrere) neue * d - (delete) löscht die passende Zeile * i - (insert) fügt eine Zeile vor der Zeile ein auf die regex zutrifft * l - (listing) zeigt nicht druckbare Zeichen an * p - (print) gibt die Zeile aus * r - (read) lese Zeilen aus Datei * s - (substitute) ersetze Zeichenfolge in zutreffender Zeile durch eine andere * w - (write) schreibe Zeilen in Datei * ! - (Negation) wendet die Befehle auf die Zeilen an, auf die regex nicht zutrifft ---- Die Substiution von Zeichenfolgen ================================= * Das Substitutionskommando kann noch mit einigen Argumenten ergänzt werden: * s/.../.../g - ersetze global (in jeder zutreffenden Zeile der Datei) * s/.../.../p - drucke passende Zeilen auf stdout * s/.../.../w - tausche Inhalt des Zwischenspeichers mit treffender Zeile ---- Viel verwendete Schalter für sed ================================ * -n - schaltet die Ausgabe des Puffers (Patternspace) aus * -e - führe mehrere Befehle nacheinander aus, Miniscript in der Kommandozeile ausführen * -f - führe Datei (sed-script) aus ## sed -n -e 's/[[:space:]]$//' <datei..........leerzeichen am ende von Zeilen löschen ---- //etc/passwd Benutzernamen mit 'Benutzer' ersetzen (vll. auch Benutzer1, Benutzer2..) ---- awk === * Interpretierte Programmiersprache mit vielen Ähnlichkeiten zu C * versteht die gleichen arithmetischen Operatoren wie C * Verarbeitung von Zeichenketten * kann man sich als "pseudo C-Interpreter" vorstellen * in den 70ern entwickelt von A. Aho, B. W. Kernighan and P. Weinberger => Name, Bell Labs ---- Struktur eines awk-Programmes ============================= .. code:: shell-session muster { aktion } ---- * Die Schlüsselwörter BEGIN und END kennzeichnen einen Block von Anweisungen, der ausgeführt werden soll, bevor irgendwelche weiteren Zeilen gelesen werden .. code:: shell-session BEGIN { aktion } { noch eine aktion } END { aktion } ---- * Feld-Operatoren werden in der Form $n, wobei n eine Zahl ist, geschrieben .. code:: shell-session ls -l | awk '{ print $9, "\t", $3 }' ---- * speziell: $0 gibt das gesamte Feld zurück ---- Arithmetische Ausdrücke ======================= * +, -, *, /, % * Besonderheit: ein Leerzeichen bedeutet 'hänge die folgende Zeichenkette an' Welcher Wert wird der Variablen x zugewiesen? .. code:: shell-session x=1+5*2 3 awk 'BEGIN { x=5+4 5; print x;}' ---- Zuweisungsoperatoren ==================== * += Addiere Ergebnis zur Variablen * -= Subtrahiere Ergebnis von der Variablen * *= Multipliziere Variable mit dem Ergebnis * /= Teile Variable durch das Ergebnis * %= Modulo Variable durch Ergebnis ---- Relationale Operatoren ====================== * == , != , > , >= , < , <= ---- Reguläre Ausdrücke ================== * ~ : trifft zu auf /regex/ * !~ : trifft nicht zu auf /regex/ ---- Boolean ======= * && und || Unär ==== * ! ---- AWK Kommandos ============= * if ( kondition ) [ else anweisung ] * while ( kondition ) anweisung * for ( ausdruck ; kondition ; ausdruck ) anweisung * for ( variable in feld ) anweisung * break * continue * { [ anweisung ] ...} * variable=ausdruck * print [ liste-von-ausdrücken ] [ > ausdruck ] * printf format [ , liste-von-ausdrücken ] [ > ausdruck ] * next * exit awk -F: '{ if ($2 == "") print $1 ": hat kein Passwort!" }' </etc/passwd ---- vordefinierte Variablen ======================= * Input Field Separator: - Kommandozeile awk -F - in einem Skript { FS=":"; } - bash: IFS - standardmäig Leerzeichen * OFS - Output Field Separator: - Standard: Leerzeichen ---- * NF - Number of Fields * NR - Number of Records awk '{ s += $1; } END { print "Summe:", s, "durchschnittl.:", s/NR }' <daten * RS - Record Separator * ORS - Output Record Separator * FILENAME - aktueller Dateiname ( der Datei, die verarbeitet wird ) ---- Kleinkram! ========== ---- Einstieg: ls & nl ================= * ls: Inhalt von Verzeichnissen ausgeben * nl: Zeilen nummerieren ---- Anknüpfungspunkte ================= .. code:: shell-session ls -l | nl * Aufgabe: den git-Commits eines Branches aufsteigende Nummern zuordnen ---- Einstieg: date & read ===================== * date: Datum ausgeben; aktuellen Zeitstempel ermitteln * read: Zeileninhalt in Variable(n) übertragen ---- Für das Protokoll ================= .. code:: shell-session ( start_epoch=$(date +%s) read beschreibung dauer=$(( ($(date +%s) - start_epoch) / 60)) echo "$dauer $beschreibung" >>spass.log ) ---- Für das Protokoll ================= * Aufgabe 1: Ermittle deine gesamte Spassdauer * Aufgabe 2: Veraendere den Aufruf, auf dass taeglich eine neue spass-Datei angelegt wird ---- Einstieg: find & xargs ====================== * find: Dateisystemobjekte nach Kriterien auflisten * xargs: Standardeingabe in Parameter umwandeln ---- Mundstopfer =========== .. code:: shell-session find /home -maxdepth 2 -type f -name .xsession-errors -delete find /home -maxdepth 2 -type f -name .xsession-errors | xargs rm ---- Mundstopfer =========== * Aufgabe 1: Sicheres Löschen der Informationen * Aufgabe 2: keine Fehlermeldung, falls keine Dateien gefunden wurden * Aufgabe 3: Sicherer Umgang mit Nutzernamen, die einen Zeilenumbruch enthalten ---- Einstieg: df & sort & cut & mailx ================================= * df: freier und benutzer Speicher von eingehängten Dateisystemen * sort: numerisches oder alphabetisches Sortieren von Zeilen * cut: spaltenweise Filtern * mailx: nicht-interaktiver Mailversand mit vielen Optionen ---- Klaustrophobia ============== .. code:: shell-session df | sed 1d | awk '{ if ($4 < 100000) print $0; }' ---- Klaustrophobia ============== * Sortierung nach dem verfügbaren Speicherplatz * Aufgabe: Formulierung als cron-job-taugliche Zeile mit Mailversand bei Speichermangel ---- Einstieg: dd & Funktionen ========================= * dd: blockweises Lesen und Schreiben * Funktionen: Sub-Shell für separate Aufgaben ---- Heuhaufen ========= .. code:: shell-session ( read_byte() { local char=$(dd bs=1 count=1); echo -n "$char"; [ -n "$char" ]; } while read_byte; do dd if=/dev/urandom bs=23 count=1; done ) 2>/dev/null <geheimnis >versteckt ---- Heuhaufen ========= * Aufgabe 1: Entschlüssele den Text! * Aufgabe 2: Vernichte das Geheimnis nach erfolgreicher Versteckung. ---- Einstieg: sleep & head & tail ============================= * sleep: Wartezeit * head / tail: führende/abschließende Zeilen ausgeben ---- Prozesspathologie ================= .. code:: shell-session ( while sleep 5; do top -b -n 1 -o "%MEM" | head -12 | tail -5 | sed "s/^/$(date +%Y%m%d%H%M%S) /" done >>nirwana.log ) ---- Prozesspathologie ================= * Aufgabe 1: Anzeige der aktuellen Zeilen auch auf der Konsole (parallel zum Loggen in der Datei). * Aufgabe 2: Sicherstellen, dass die Datei auch wirklich geschrieben wird, bevor das System neustartet. * Aufgabe 3: Ermitteln der Prozesszeile zum Zeitpunkt des maximalen Speicherbedarfs eines Prozesses. ---- Einstieg: ps & who ================== * ps: Prozesse auflisten * who: angemeldete Nutzer auflisten ---- Jagd auf Ikarus =============== .. code:: shell-session watch "ps -ef | grep sudo | grep -v grep" ---- Jagd auf Ikarus =============== * Aufgabe: Wem gehört der Prozess? ---- Einstieg: basename & wc ======================= * basename: Dateinamen aus einem Pfad extrahieren * wc: zählen von Zeichen, Worten und Zeilen Rundungsfehler ============== .. code:: shell-session find ~ -type f | xargs -n 1 basename | wc | awk '{ print $3 / $1 - 1; }' ---- Rundungsfehler ============== * Aufgabe: Stelle sicher, dass dies auch mit Dateinamen funktioniert, die Zeilenumbrüche enthalten. ---- Übersehene Helfer ================= * Dateien: cp / mv / rm / rmdir / touch * Text: cat / cut / join / tr / uniq * System / Prozesse: chroot / dirname / du / expr / factor / id / nice / printf / pwd / readlink / seq / stat / test / timeout / true / false / uname / uptime