Crewlove – Kapitel 30: RegulĂ€re AusdrĂŒcke (Regex)

Crewlove-Notiz: Regex ist wie eine Spur im Log-Wald: du siehst nicht alles – aber du erkennst Muster.


30.0 Was ist ein regulÀrer Ausdruck?

Ein regulĂ€rer Ausdruck (kurz Regex / RegExp) ist eine kompakte Schreibweise, um Muster in Texten zu beschreiben – zum Suchen, Filtern, Extrahieren und Ersetzen.

Du findest Regex in vielen Umgebungen:

  • Python (re)
  • JavaScript (RegExp, /.../)
  • PHP (preg_*)
  • Shell-Tools wie grep, sed, awk, perl
  • Editor-Suche (VS Code, Sublime, 
)

30.1 Grundbegriffe – fang klein an

Symbol Bedeutung Mini-Beispiel
. beliebiges Zeichen (außer Zeilenumbruch) a.c → abc, axc
* 0 oder mehr Wiederholungen ab*c → ac, abc, abbc
+ 1 oder mehr Wiederholungen ab+c → abc, abbc
? 0 oder 1 Wiederholung colou?r → color, colour
^ Start der Zeile ^Hello
$ Ende der Zeile world$
[...] Zeichenmenge [abc]
(...) Gruppierung (Capture) (\d{2})/(\d{4})
| ODER cat | dog
\d Ziffer \d+
\w Wort-Zeichen \w+

Tipps:

  • Starte mit einem Mini-Text wie "Hello world".
  • Teste live im Regex-Tester, bevor du es ins Skript packst.

30.2 Lernpfad – Schritt fĂŒr Schritt

Stufe Fokus
0 Metazeichen verstehen (.^$*+?[]())
1 Muster fĂŒr Alltag (E-Mail, Zahlen, IDs)
2 Gruppen & Referenzen ((...), $1)
3 Lookarounds (wenn deine Engine es kann)
4 Matches im Code extrahieren (Python/JS/PHP)
5 Üben mit echten Projekttexten (Logs/Configs/CSV)
6 Kleine Übungsskripte (10 Aufgaben → Routine)
7 Flags lernen (i, m, s, g, 
 je nach Tool)

30.3 Werkzeuge

Online-Tester

  • regex101.com
  • regexr.com
  • debuggex.com

Merke: Nicht jede Regex-Engine kann alles.

  • grep -E (ERE) ist anders als grep -P (PCRE)
  • awk folgt POSIX-Regex (keine PCRE-Lookbehinds)

30.4 Mini-Übung: Zeilen mit ERROR aus einer Logdatei

Python

import re

with open('log.txt', encoding='utf-8') as f:
    for line in f:
        if re.search(r'^ERROR', line):
            print(line.rstrip())

Node.js

const fs = require('fs');
const text = fs.readFileSync('log.txt', 'utf8');

text.split('\n').forEach(line => {
  if (/^ERROR/.test(line)) console.log(line);
});

30.5 Greedy vs Non‑Greedy

  • Greedy: .* nimmt „so viel wie möglich“.
  • Non‑Greedy: .*? nimmt „so wenig wie möglich“.

Beispiel:

  • <.*> frisst zu viel
  • <.*?> stoppt frĂŒher

30.6 Regex im Terminal: grep & awk

grep Basics

grep -i '^error' datei.txt

grep ERE (Extended)

grep -E 'open|close' datei.txt
grep -E '[0-9]{3}' logfile.txt

awk filtert Zeilen mit Regex

awk '/ERROR/ {print NR ":" $0}' logfile.txt

30.7 Crumbforest-Praxis: Nginx Accesslog Pfade zÀhlen

A) PCRE-Variante (grep -P)

grep -oP '(?<=GET\s)[^\s"]+(?=\sHTTP/\d+\.\d+")' /var/log/nginx/access.log \
| awk '{ c[tolower($0)]++ } END{ for (u in c) printf "%5d  %s\n", c[u], u }' \
| sort -nr

B) Nur awk (robust, ohne grep -P)

awk '
  match($0, /"GET ([^ ]+) HTTP\/[0-9.]+"/, m) {
    p = tolower(m[1]); c[p]++
  }
  END { for (p in c) printf "%5d  %s\n", c[p], p }
' /var/log/nginx/access.log | sort -nr

Warum B oft besser ist:

  • lĂ€uft auch ohne PCRE
  • weniger Shell-Quoting-Probleme
  • schnell fĂŒr große Logs

30.8 HĂ€ufige Stolperfallen

Stolperfalle Kurzlösung
. matcht keinen Zeilenumbruch Flag s/DOTALL oder [\s\S]
Escape vergessen (. statt \.) Punkt immer escapen, wenn literal
PCRE vs POSIX verwechselt Tool/Engine checken (grep -E vs -P)
\b in awk In POSIX awk ist \b kein Word-Boundary

30.9 Kurzantwort (3 Zeilen)

^      – Anfang einer Zeile
$      – Ende einer Zeile
.*?    – beliebige Zeichen, möglichst kurz

Abschluss

Regex ist kein „Dark Art“.
Es ist ein Muster-Licht im Textwald.
Und wenn du Logs lesen kannst, kannst du auch Spuren lesen.

crewlove 🩉🩊đŸŒČ

Kapitel 31: sed – der Stream-Editor

Bild: sed ist wie ein kleines Messer am Fluss: du schneidest Muster aus dem Textstrom und formst ihn neu.

31.1 Die Grundform

sed -E 's/REGEX/REPLACE/' file.txt
  • s/// = substitution (ersetzen)
  • ohne g wird nur das erste Match pro Zeile ersetzt
  • mit g werden alle Matches pro Zeile ersetzt

31.2 Sicher arbeiten: erst anschauen, dann anwenden

Nur zeigen (dry-run):

sed -E 's/foo/bar/g' file.txt | less

Nur Zeilen ausgeben, die sich Ă€ndern wĂŒrden:

sed -nE 's/foo/bar/gp' file.txt
  • -n unterdrĂŒckt Standard-Ausgabe
  • p druckt nur, wenn die Ersetzung passiert ist

31.3 Klassiker: Dateiendung in einer Liste Àndern (Textliste)

sed -E 's/\.txt$/.doc/' names.txt
  • \. = echter Punkt
  • $ = Ende der Zeile → nur Endungen, keine inneren Treffer

31.4 Log-Politur: doppelte Spaces → ein Space

sed -E 's/[[:space:]]+/ /g' logfile.txt

31.5 Stolperstein: GNU vs BSD (macOS)

  • Oft klappt auf macOS auch sed -E gut.
  • GNU sed kennt ebenfalls -E (frĂŒher oft -r).

Kapitel 32: awk – die Wald-Rechenmaschine

Bild: awk ist ein kleines Programm pro Zeile: du kannst filtern, zÀhlen, gruppieren, berichten.

32.1 Felder & Standard-Variablen

  • $0 = ganze Zeile
  • $1, $2, 
 = Felder (standard: getrennt durch Spaces/Tabs)
  • NF = Anzahl Felder
  • NR = Zeilennummer

Beispiel: zweite Spalte ausgeben

awk '{print $2}' file.txt

CSV (Komma) lesen

awk -F',' '{print $1, $3}' data.csv

32.2 Substitution: sub vs gsub

  • sub(r, repl) ersetzt nur das erste Match in $0
  • gsub(r, repl) ersetzt alle Matches
echo 'foo foo' | awk '{ sub(/foo/,"bar"); print }'
# → bar foo

32.3 ZĂ€hlen: assoziative Arrays

Wie oft kommt ein Wort in einer Datei vor?

awk '{ c[$0]++ } END { for (k in c) printf "%5d  %s\n", c[k], k }' list.txt | sort -nr

32.4 Match & Gruppen: Pfade aus Nginx-Accesslog zÀhlen (awk-only)

awk '
  match($0, /"GET ([^ ]+) HTTP\/[0-9.]+"/, m) {
    p = tolower(m[1]); c[p]++
  }
  END { for (p in c) printf "%5d  %s\n", c[p], p }
' /var/log/nginx/access.log | sort -nr

32.5 Mini-Report: Statuscodes zÀhlen

awk '
  { code=$9; if (code ~ /^[0-9]{3}$/) c[code]++ }
  END { for (k in c) printf "%6d  %s\n", c[k], k }
' /var/log/nginx/access.log | sort -nr

Kapitel 33: grep – die SpĂŒrnase

#kein #krĂŒmel #geht #verloren: grep ist die Taschenlampe im Unterholz.

33.1 Drei Modi: schnell, flexibel, mÀchtig

  • grep -F → Fixed strings (am schnellsten, keine Regex)
  • grep -E → Extended Regex (ERE: + ? | {} ohne Backslashes)
  • grep -P → PCRE (Lookarounds & mehr, falls verfĂŒgbar)

33.2 HĂ€ufige Flags

Flag Bedeutung
-n Zeilennummern
-r / -R rekursiv (Verzeichnisse)
-i ignore case
-v invert (alles außer Treffer)
-c zÀhlen
-o nur Match ausgeben
-w ganzes Wort
-x ganze Zeile muss matchen
-m 1 nach 1 Treffer stoppen
-C 2 Kontext: 2 Zeilen davor/danach

33.3 Beispiele, die du stÀndig brauchst

Fehler im Log finden (mit Kontext):

grep -nC 2 -E 'ERROR|FATAL' app.log

Alles außer Kommentare & leere Zeilen:

grep -vE '^[[:space:]]*(#|$)' config.conf

Nur die Pfade aus Accesslog (PCRE):

grep -oP '(?<=GET\s)[^\s"]+(?=\sHTTP/\d+\.\d+")' /var/log/nginx/access.log

Top-Pfade zĂ€hlen (grep → awk):

grep -oP '(?<=GET\s)[^\s"]+(?=\sHTTP/\d+\.\d+")' /var/log/nginx/access.log \
| awk '{ c[tolower($0)]++ } END { for (k in c) printf "%5d  %s\n", c[k], k }' \
| sort -nr | head

33.4 Pro-Tipp: Erst -F, dann Regex

Wenn du nach einem fixen String suchst (z. B. "timeout"), nimm -F:

grep -nF 'timeout' app.log

Regex ist mĂ€chtiger – aber -F ist oft schneller und sicherer.


Schluss

Mit sed formst du den Fluss,
mit awk zÀhlst du die Spuren,
mit grep findest du jeden KrĂŒmel.

#kein #krĂŒmel #geht #verloren <3

crewlove 🩉🩊đŸŒČ