# awk — Feldbasierte Textverarbeitung und Auswertung

> Spaltenbasierten Text mit awk verarbeiten — Felder extrahieren, nach Mustern filtern, mit Arrays aggregieren und Ausgaben formatieren.

Source: https://www.jpkc.com/db/cheatsheets/files-text/awk/

<!-- PROSE:intro -->
awk ist eine kleine, aber vollständige Programmiersprache für spaltenbasierten Text. Es liest die Eingabe Zeile für Zeile, zerlegt jede Zeile in Felder (`$1`, `$2`, … `$NF`) und führt dein Programm für jeden Datensatz aus – damit ist es die naheliegende Wahl für Logdateien, CSV-/TSV-Daten und tabellarische Befehlsausgaben. Während grep Zeilen findet und sed sie umschreibt, kannst du mit awk nach Feldern selektieren, Summen und Mittelwerte berechnen, mit assoziativen Arrays Häufigkeitstabellen aufbauen und sauber formatierte Auswertungen ausgeben. Dieser Guide behandelt das Wesentliche: Felder und Trenner, Mustererkennung, Bedingungen, `BEGIN`-/`END`-Blöcke, Arithmetik, String-Funktionen und die Rezepte, zu denen du immer wieder greifst.
<!-- PROSE:intro:end -->

## Grundlagen

`awk '{print}' <file>` — Gibt jede Zeile der Datei aus (wie cat).

```bash
awk '{print}' data.txt
```

`awk '{print $0}' <file>` — Gibt jede ganze Zeile aus. $0 steht für die gesamte Zeile.

```bash
awk '{print $0}' data.txt
```

`awk '{print $1}' <file>` — Gibt das erste Feld (die erste Spalte) jeder Zeile aus. Felder werden per Whitespace getrennt.

```bash
awk '{print $1}' access.log
```

`awk '{print $1, $3}' <file>` — Gibt bestimmte Felder durch ein Leerzeichen getrennt aus (Output Field Separator).

```bash
awk '{print $1, $3}' data.txt
```

`awk '{print $NF}' <file>` — Gibt das letzte Feld jeder Zeile aus. NF ist die Anzahl der Felder.

```bash
awk '{print $NF}' access.log
```

`awk '{print $(NF-1)}' <file>` — Gibt das vorletzte Feld jeder Zeile aus.

```bash
awk '{print $(NF-1)}' data.txt
```

`awk 'NR==<n>' <file>` — Gibt nur eine bestimmte Zeilennummer aus. NR ist die Nummer des aktuellen Datensatzes (der aktuellen Zeile).

```bash
awk 'NR==5' data.txt
```

`awk 'NR>=<n> && NR<=<m>' <file>` — Gibt einen Zeilenbereich aus.

```bash
awk 'NR>=10 && NR<=20' data.txt
```

## Feldtrenner

`awk -F'<sep>' '{print $1}' <file>` — Legt einen eigenen Eingabe-Feldtrenner fest.

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

`awk -F':' '{print $1, $3}' <file>` — Verwendet den Doppelpunkt als Feldtrenner (nützlich für /etc/passwd).

```bash
awk -F':' '{print $1, $3}' /etc/passwd
```

`awk -F'\t' '{print $2}' <file>` — Verwendet den Tabulator als Feldtrenner für TSV-Dateien.

```bash
awk -F'\t' '{print $2}' data.tsv
```

`awk -F'[,;:]' '{print $1}' <file>` — Verwendet eine Regex als Feldtrenner (trifft auf jedes der Zeichen).

```bash
awk -F'[,;:]' '{print $1}' mixed.txt
```

`awk 'BEGIN{FS=","; OFS="\t"} {print $1, $2}' <file>` — Legt Eingabe-Feldtrenner (FS) und Ausgabe-Feldtrenner (OFS) fest.

```bash
awk 'BEGIN{FS=","; OFS="\t"} {print $1, $2}' data.csv
```

`awk -v OFS=',' '{$1=$1; print}' <file>` — Ändert den Ausgabetrenner. Der Trick $1=$1 zwingt awk, die Zeile neu aufzubauen.

```bash
awk -v OFS=',' '{$1=$1; print}' whitespace.txt
```

## Mustererkennung

`awk '/<pattern>/' <file>` — Gibt Zeilen aus, die auf ein Regex-Muster passen (wie grep).

```bash
awk '/ERROR/' log.txt
```

`awk '!/<pattern>/' <file>` — Gibt Zeilen aus, die NICHT auf ein Muster passen (wie grep -v).

```bash
awk '!/^#/' config.ini
```

`awk '$<n> ~ /<pattern>/' <file>` — Gleicht ein Muster gegen ein bestimmtes Feld ab.

```bash
awk '$3 ~ /error/' log.txt
```

`awk '$<n> !~ /<pattern>/' <file>` — Gibt Zeilen aus, bei denen ein bestimmtes Feld NICHT auf ein Muster passt.

```bash
awk '$1 !~ /^192\.168/' access.log
```

`awk '/<start>/,/<end>/' <file>` — Gibt Zeilen zwischen zwei Mustern aus (einschließender Bereich).

```bash
awk '/BEGIN/,/END/' config.txt
```

`awk '/pattern/ {print $2}' <file>` — Gibt nur ein bestimmtes Feld aus Zeilen aus, die auf ein Muster passen.

```bash
awk '/GET/ {print $7}' access.log
```

## Bedingungen & Vergleiche

`awk '$<n> == "<value>"' <file>` — Gibt Zeilen aus, bei denen ein Feld einer bestimmten Zeichenkette entspricht.

```bash
awk '$3 == "ERROR"' log.txt
```

`awk '$<n> != "<value>"' <file>` — Gibt Zeilen aus, bei denen ein Feld einem Wert nicht entspricht.

```bash
awk '$1 != "localhost"' hosts.txt
```

`awk '$<n> > <value>' <file>` — Gibt Zeilen aus, bei denen ein numerisches Feld einen Schwellwert überschreitet.

```bash
awk '$5 > 1000' data.txt
```

`awk '$<n> > <value> && $<m> < <value>' <file>` — Kombiniert mehrere Bedingungen mit && (UND).

```bash
awk '$3 > 100 && $4 < 500' sales.txt
```

`awk '$<n> > <value> || $<m> == "<value>"' <file>` — Kombiniert Bedingungen mit || (ODER).

```bash
awk '$5 > 1000 || $3 == "CRITICAL"' log.txt
```

`awk 'NF > 0' <file>` — Gibt nur nicht-leere Zeilen aus (Zeilen mit mindestens einem Feld).

```bash
awk 'NF > 0' messy.txt
```

`awk 'NF == <n>' <file>` — Gibt Zeilen mit genau N Feldern aus.

```bash
awk 'NF == 4' data.txt
```

`awk 'length > <n>' <file>` — Gibt Zeilen aus, die länger als N Zeichen sind.

```bash
awk 'length > 80' source.py
```

## BEGIN- & END-Blöcke

`awk 'BEGIN {print "Header"} {print} END {print "Footer"}' <file>` — Führt Code vor der Verarbeitung (BEGIN) und nach allen Zeilen (END) aus.

```bash
awk 'BEGIN {print "Name\tScore"} {print $1"\t"$2} END {print "---"}' results.txt
```

`awk 'BEGIN {<init>} {<body>} END {<summary>}' <file>` — Klassische awk-Struktur: initialisieren, jede Zeile verarbeiten, dann zusammenfassen.

```bash
awk 'BEGIN {sum=0} {sum+=$1} END {print "Total:", sum}' numbers.txt
```

`awk 'END {print NR}' <file>` — Gibt die Gesamtzahl der Zeilen einer Datei aus.

```bash
awk 'END {print NR}' data.txt
```

`awk 'END {print NR, "lines,", NF, "fields in last line"}' <file>` — Gibt nach der Verarbeitung aller Zeilen eine Zusammenfassung aus.

```bash
awk 'END {print NR, "lines processed"}' access.log
```

## Arithmetik & Aggregation

`awk '{sum += $<n>} END {print sum}' <file>` — Summiert alle Werte einer bestimmten Spalte.

```bash
awk '{sum += $3} END {print sum}' sales.txt
```

`awk '{sum += $<n>} END {print sum/NR}' <file>` — Berechnet den Durchschnitt einer Spalte.

```bash
awk '{sum += $2} END {print "Average:", sum/NR}' scores.txt
```

`awk 'BEGIN {max=0} {if ($<n> > max) max=$<n>} END {print max}' <file>` — Findet den größten Wert in einer Spalte.

```bash
awk 'BEGIN {max=0} {if ($3 > max) max=$3} END {print "Max:", max}' data.txt
```

`awk 'NR==1 || $<n> < min {min=$<n>} END {print min}' <file>` — Findet den kleinsten Wert in einer Spalte.

```bash
awk 'NR==1 || $2 < min {min=$2} END {print "Min:", min}' data.txt
```

`awk '{count[$<n>]++} END {for (k in count) print k, count[k]}' <file>` — Zählt das Vorkommen jedes eindeutigen Werts in einer Spalte (Häufigkeitstabelle).

```bash
awk '{count[$1]++} END {for (ip in count) print ip, count[ip]}' access.log
```

`awk '{sum[$1] += $2} END {for (k in sum) print k, sum[k]}' <file>` — Summiert Werte gruppiert nach einer Schlüsselspalte (wie SQL GROUP BY).

```bash
awk '{sum[$1] += $3} END {for (dept in sum) print dept, sum[dept]}' expenses.txt
```

## String-Funktionen

`awk '{print length($0)}' <file>` — Gibt die Länge jeder Zeile aus.

```bash
awk '{print length($0), $0}' data.txt
```

`awk '{print toupper($0)}' <file>` — Wandelt jede Zeile in Großbuchstaben um.

```bash
awk '{print toupper($0)}' input.txt
```

`awk '{print tolower($0)}' <file>` — Wandelt jede Zeile in Kleinbuchstaben um.

```bash
awk '{print tolower($0)}' input.txt
```

`awk '{gsub(/<pattern>/, "<replacement>"); print}' <file>` — Globale Ersetzung in jeder Zeile (wie sed s///g).

```bash
awk '{gsub(/foo/, "bar"); print}' input.txt
```

`awk '{sub(/<pattern>/, "<replacement>"); print}' <file>` — Ersetzt nur das erste Vorkommen in jeder Zeile.

```bash
awk '{sub(/^[ \t]+/, ""); print}' messy.txt
```

`awk '{print substr($0, <start>, <length>)}' <file>` — Extrahiert eine Teilzeichenkette aus jeder Zeile (1-basierte Startposition).

```bash
awk '{print substr($0, 1, 10)}' data.txt
```

`awk '{n=split($0, arr, "<sep>"); print arr[1]}' <file>` — Zerlegt eine Zeichenkette anhand eines Trenners in ein Array. Gibt die Anzahl der Elemente zurück.

```bash
awk '{n=split($0, parts, ","); print parts[2]}' data.csv
```

`awk 'match($0, /<pattern>/) {print substr($0, RSTART, RLENGTH)}' <file>` — Extrahiert den von einer Regex gefundenen Teil. Setzt RSTART und RLENGTH.

```bash
awk 'match($0, /[0-9]+\.[0-9]+/) {print substr($0, RSTART, RLENGTH)}' data.txt
```

## Formatierte Ausgabe

`awk '{printf "%-20s %s\n", $1, $2}' <file>` — Gibt mit printf formatierte, ausgerichtete Spalten aus.

```bash
awk '{printf "%-20s %10s\n", $1, $2}' data.txt
```

`awk '{printf "%05d %s\n", NR, $0}' <file>` — Gibt Zeilennummern auf 5 Stellen mit Nullen aufgefüllt aus.

```bash
awk '{printf "%05d %s\n", NR, $0}' script.sh
```

`awk '{printf "%.2f\n", $1}' <file>` — Formatiert Zahlen mit 2 Nachkommastellen.

```bash
awk '{printf "$%.2f\n", $3}' prices.txt
```

`awk '{printf "%s,%s,%s\n", $1, $2, $3}' <file>` — Wandelt durch Whitespace getrennte Daten in CSV um.

```bash
awk '{printf "%s,%s,%s\n", $1, $2, $3}' data.txt
```

`awk -v OFS='\t' '{$1=$1; print}' <file>` — Wandelt beliebige Whitespace-Trennung in tabulatorgetrennte Ausgabe um.

```bash
awk -v OFS='\t' '{$1=$1; print}' data.txt
```

## Variablen & Zuweisung

`awk -v <var>=<value> '{print <var>, $1}' <file>` — Übergibt eine externe Variable an das awk-Programm.

```bash
awk -v threshold=100 '$3 > threshold {print}' data.txt
```

`awk -v var="$SHELL_VAR" '{print var, $0}' <file>` — Übergibt eine Shell-Variable an awk.

```bash
awk -v user="$USER" '{print user, $0}' log.txt
```

`awk '{$<n> = "<value>"; print}' <file>` — Ersetzt den Wert eines bestimmten Felds und gibt die geänderte Zeile aus.

```bash
awk '{$2 = "REDACTED"; print}' users.txt
```

`awk '{$(NF+1) = "<value>"; print}' <file>` — Hängt ein neues Feld an das Ende jeder Zeile an.

```bash
awk -v OFS=',' '{$(NF+1) = "new_col"; print}' data.csv
```

## Arrays & Deduplizierung

`awk '!seen[$0]++' <file>` — Entfernt doppelte Zeilen unter Beibehaltung der Reihenfolge (wie sort -u, aber ohne zu sortieren).

```bash
awk '!seen[$0]++' list.txt
```

`awk '!seen[$<n>]++' <file>` — Entfernt Duplikate anhand eines bestimmten Felds.

```bash
awk '!seen[$1]++' data.txt
```

`awk '{a[$1]+=$2} END {for (k in a) print k, a[k]}' <file>` — Aggregiert Werte nach Schlüssel mithilfe eines assoziativen Arrays.

```bash
awk -F',' '{a[$1]+=$2} END {for (k in a) print k, a[k]}' sales.csv
```

`awk '{a[$1]++} END {for (k in a) if (a[k]>1) print k, a[k]}' <file>` — Findet und gibt nur doppelte Einträge aus.

```bash
awk '{a[$1]++} END {for (k in a) if (a[k]>1) print k, a[k]}' access.log
```

`awk '{a[NR]=$0} END {for (i=NR; i>=1; i--) print a[i]}' <file>` — Kehrt die Reihenfolge der Zeilen um (wie tac).

```bash
awk '{a[NR]=$0} END {for (i=NR; i>=1; i--) print a[i]}' data.txt
```

## Mehrere Dateien & Pipelines

`<command> | awk '{print $<n>}'` — Extrahiert eine bestimmte Spalte aus einer Befehlsausgabe.

```bash
ps aux | awk '{print $1, $11}'
```

`<command> | awk 'NR>1 {print $<n>}'` — Extrahiert eine Spalte aus einer Befehlsausgabe und überspringt die Kopfzeile.

```bash
df -h | awk 'NR>1 {print $1, $5}'
```

`awk 'FNR==1 {print "--- " FILENAME " ---"} {print}' <file1> <file2>` — Verarbeitet mehrere Dateien mit einem Trenner. FNR wird pro Datei zurückgesetzt, FILENAME enthält den Namen.

```bash
awk 'FNR==1 {print "--- " FILENAME " ---"} {print}' *.log
```

`awk '{print > "output_" $<n> ".txt"}' <file>` — Teilt eine Datei anhand eines Feldwerts in mehrere Dateien auf.

```bash
awk -F',' '{print > "dept_" $1 ".csv"}' employees.csv
```

`awk '{print | "sort"}' <file>` — Leitet die awk-Ausgabe an einen externen Befehl weiter.

```bash
awk '{print $1}' access.log | sort | uniq -c | sort -rn
```

## Häufige Rezepte

`awk -F',' 'NR==1 {for (i=1;i<=NF;i++) header[i]=$i} NR>1 {for (i=1;i<=NF;i++) print header[i]": "$i; print ""}' <file>` — Stellt CSV-Daten vertikal dar, mit den Spaltenüberschriften als Beschriftung.

```bash
awk -F',' 'NR==1 {for (i=1;i<=NF;i++) h[i]=$i} NR>1 {for (i=1;i<=NF;i++) print h[i]": "$i; print ""}' users.csv
```

`awk '{for (i=NF; i>0; i--) printf "%s ", $i; printf "\n"}' <file>` — Kehrt die Feldreihenfolge in jeder Zeile um.

```bash
awk '{for (i=NF; i>0; i--) printf "%s ", $i; printf "\n"}' data.txt
```

`awk 'NR==FNR {a[$1]; next} $1 in a' <file1> <file2>` — Gibt Zeilen aus file2 aus, deren erstes Feld in file1 vorkommt (wie ein Join/Lookup).

```bash
awk 'NR==FNR {a[$1]; next} $1 in a' ids.txt data.txt
```

`awk '{sum=0; for(i=1;i<=NF;i++) sum+=$i; print sum}' <file>` — Summiert alle Felder einer Zeile (Zeilensummen).

```bash
awk '{sum=0; for(i=1;i<=NF;i++) sum+=$i; print $0, sum}' matrix.txt
```

`awk 'NR%<n>==0' <file>` — Gibt jede N-te Zeile aus.

```bash
awk 'NR%5==0' data.txt
```

`awk '{$1=""; print substr($0,2)}' <file>` — Entfernt das erste Feld und gibt den Rest der Zeile aus.

```bash
awk '{$1=""; print substr($0,2)}' data.txt
```

<!-- PROSE:outro -->
## Fazit

awk spielt seine Stärken in dem Moment aus, in dem deine Daten Spalten haben: `awk '{print $2}'`, ein schnelles `sum += $3` in einem `END`-Block oder eine einzeilige Häufigkeitstabelle mit `count[$1]++` ersetzt oft ein ganzes Skript. Beginne mit `-F`, um den Feldtrenner zu setzen, stütze dich auf `NR`/`NF` für Zeilen- und Feldzahlen, und denke daran: awk liest die Eingabe, ohne deine Dateien zu verändern – die Ausgabe geht nach stdout, leite sie also bewusst um, wenn du Ergebnisse zurückschreibst. Eine häufige Stolperfalle: awk-Regex-Literale kennen kein `/i`-Flag, für eine Suche ohne Beachtung der Groß-/Kleinschreibung nutzt du daher gawks `IGNORECASE=1` oder `tolower()`. Für alles jenseits weniger Zeilen ist GNU-awk (gawk) die leistungsfähigste und am weitesten verbreitete Implementierung.

## Weiterführende Links

- [GNU-awk-(gawk)-Handbuch](https://www.gnu.org/software/gawk/manual/gawk.html) – umfassende Referenz zur Sprache (englisch)
- [ubuntuusers-Wiki: awk](https://wiki.ubuntuusers.de/awk/) – deutschsprachige Einführung mit praktischen Beispielen
<!-- PROSE:outro:end -->

## Verwandte Kommandos

- [sed](https://www.jpkc.com/db/cheatsheets/files-text/sed/) – Stream-Editor zum Ersetzen und für zeilenweise Änderungen
- [grep](https://www.jpkc.com/db/cheatsheets/files-text/grep/) – schnelle Mustersuche, um Zeilen für awk vorzufiltern
- [cut](https://www.jpkc.com/db/cheatsheets/files-text/cut/) – leichtgewichtige Feldextraktion für einfache Spaltenaufgaben

