awk ist mehr als ein Befehl — es ist eine kleine Programmiersprache, spezialisiert auf spaltenorientierte Texte. Per Default zerlegt awk jede Eingabezeile in Felder ($1, $2, …) und wendet Regeln nach dem Schema Pattern → Action an. Damit werden Logs gefiltert, CSV-Spalten extrahiert, Summen gezogen und Häufigkeiten gezählt — alles in einem einzigen Einzeiler.
Was awk macht
awk liest Text zeilenweise, zerlegt jede Zeile automatisch an einem Field Separator (Default: Whitespace) in Felder und führt eine Reihe von Regeln darauf aus. Eine Regel besteht aus einem Pattern und einer Action — das Pattern entscheidet, ob die Action läuft, und die Action sagt, was zu tun ist. Fehlt das Pattern, gilt die Action für jede Zeile; fehlt die Action, wird die Zeile ausgegeben.
Diese Doppelnatur macht awk zum Klassiker für strukturierte Daten: Logs, /etc/passwd-ähnliche Konfigdateien, CSV-Exports, ps-Ausgaben, df-Statistiken. Überall, wo jede Zeile ein Datensatz und jedes Whitespace-getrennte Stück ein Feld ist, ist awk das richtige Werkzeug.
awk '{print $1}' datei.txtDrei awk-Implementationen
Hinter dem Namen awk stecken mehrere Implementierungen mit unterschiedlichem Funktionsumfang. Je nach System ruft awk eine andere Variante auf — was bei portablen Skripten zur Falle werden kann.
| Implementation | Herkunft | Eigenschaften |
|---|---|---|
Original awk | Aho/Weinberger/Kernighan, 1977 | Der Klassiker; minimaler Funktionsumfang, kaum noch direkt im Einsatz |
nawk (“new awk”) | 1985, POSIX-Basis | Funktionen, mehrdimensionale Arrays, dynamische Regex |
gawk (GNU awk) | GNU-Projekt | Default auf den meisten Linux-Distributionen; viele Erweiterungen |
BSD awk | macOS, FreeBSD | Schlanker als gawk, teils inkompatibel |
gawk bringt die meisten Extras mit: gensub, length(array), Netzwerk-I/O, Time-Funktionen, Internationalisierung. Auf Linux ist awk meist ein Symlink auf gawk. Auf macOS dagegen ist awk BSD-awk — wer GNU-Features nutzt, sollte sie portabel halten oder via Homebrew gawk installieren.
awk --version 2>&1 | head -1Grundsyntax: Pattern { Action }
Jede awk-Regel folgt dem Schema Pattern { Action }. Beide Teile sind optional, aber mindestens einer muss da sein. Ein leeres Pattern bedeutet “trifft auf jede Zeile zu”, eine leere Action bedeutet “gib die Zeile aus” (also { print }).
awk '{print $1}' fileawk '/ERROR/' logawk 'NR==5' fileMehrere Regeln werden einfach hintereinander geschrieben — awk probiert für jede Eingabezeile alle Regeln in der Reihenfolge ihres Auftretens. Das Skript steht entweder direkt in einfachen Quotes auf der Kommandozeile oder in einer Datei, die mit -f script.awk geladen wird.
Felder und Spezialvariablen
Die Stärke von awk liegt in seinen vordefinierten Variablen. Sie geben Zugriff auf Felder, Zeilennummern und steuern, wie Ein- und Ausgabe getrennt werden.
| Variable | Bedeutung |
|---|---|
$0 | Die komplette aktuelle Zeile |
$1, $2, … $N | Die einzelnen Felder der Zeile |
NF | Number of Fields — Anzahl der Felder in der aktuellen Zeile |
NR | Number of Records — laufende Zeilennummer über alle Eingaben |
FNR | Wie NR, aber pro Datei zurückgesetzt |
FS | Field Separator (Eingabe), Default Whitespace |
OFS | Output Field Separator, Default Leerzeichen |
RS | Record Separator (Eingabe), Default Newline |
ORS | Output Record Separator, Default Newline |
FILENAME | Name der aktuell gelesenen Datei |
FS setzt man entweder per -F auf der Kommandozeile oder im BEGIN-Block. $NF ist ein Idiom für “letztes Feld”, $(NF-1) für das vorletzte. Das Feld-Indexing ist 1-basiert — $0 ist die ganze Zeile, nicht das erste Feld.
awk -F',' '{print $2}' daten.csvawk 'BEGIN{FS=":"; OFS="|"} {print $1, $7}' /etc/passwdBEGIN und END
Zwei spezielle Patterns laufen nicht pro Zeile, sondern einmal: BEGIN vor der ersten Zeile, END nach der letzten. Damit baut man Header, Footer, Initialisierungen und Summen.
awk 'BEGIN{sum=0} {sum+=$2} END{print sum}' zahlen.txtBEGIN ist der richtige Ort, um FS, OFS und eigene Variablen zu setzen, Header auszugeben oder Lookup-Tabellen zu initialisieren. END summiert auf, druckt Statistiken oder iteriert über assoziative Arrays, die während des Hauptlaufs gefüllt wurden. Mehrere BEGIN- und END-Blöcke sind erlaubt und werden in Reihenfolge abgearbeitet.
awk 'BEGIN{print "Start"} {print NR, $0} END{print "Total:", NR}' filePattern-Typen
Patterns sind nicht auf Regex beschränkt. awk kennt mehrere Formen, die sich kombinieren lassen.
| Pattern | Bedeutung | Beispiel |
|---|---|---|
/REGEX/ | Zeile matcht Regex | /ERROR/ |
$N OPERATOR WERT | Feld-Vergleich | $3 > 100 |
/START/,/END/ | Range zwischen zwei Patterns | /BEGIN/,/END/ |
! /REGEX/ | Negation | !/DEBUG/ |
PAT1 && PAT2 | Logisches UND | $3 > 100 && /ERROR/ |
PAT1 || PAT2 | Logisches ODER | /WARN/ || /ERROR/ |
NR==N | Zeilennummer-Match | NR==1 (nur Header) |
Range-Patterns sind besonders praktisch für das Extrahieren von Blöcken — alles zwischen zwei Markern, etwa zwischen BEGIN_LOG und END_LOG. Das Range-Pattern bleibt aktiv, bis das End-Pattern matcht, und schließt beide Marker mit ein.
awk '/ERROR/ && $3 > 100 {print $0}' app.logawk '/BEGIN_BLOCK/,/END_BLOCK/' input.txtKontrollstrukturen und Built-ins
Innerhalb der Action stehen alle klassischen Kontrollstrukturen zur Verfügung: if/else, for, while, do-while, break, continue. Variablen brauchen keine Deklaration — werden sie genutzt, existieren sie. Strings und Zahlen werden bei Bedarf automatisch konvertiert.
awk '{
if ($3 > 100) print $1, "hoch"
else print $1, "niedrig"
for (i = 1; i <= NF; i++) total += $i
}' werte.txtDie wichtigsten eingebauten Funktionen:
| Funktion | Wirkung |
|---|---|
length(s) | Länge eines Strings (oder ganzer Zeile bei length()) |
substr(s, m, n) | Teilstring ab Position m, optional n Zeichen |
split(s, arr, sep) | String in Array zerlegen |
sub(re, repl, s) | Erste Regex-Trefferstelle ersetzen |
gsub(re, repl, s) | Alle Regex-Trefferstellen ersetzen |
match(s, re) | Position des ersten Regex-Treffers |
index(s, sub) | Position eines Substrings |
printf / sprintf | Formatierte Ausgabe wie in C |
int(x), rand(), srand() | Numerische Helfer |
printf mit %-20s %10.2f\n formatiert Spalten sauber — wesentlich praeziser als print mit einfachem Komma.
Assoziative Arrays
Das Killer-Feature von awk: Arrays sind immer assoziativ. Jeder String, jede Zahl kann als Schlüssel dienen — keine Initialisierung, keine Größen-Definition. Damit werden Häufigkeitsanalysen zu Einzeilern.
awk '{count[$1]++} END {for (k in count) print count[k], k}' log.txtcount[$1]++ zählt für jeden Wert in Spalte 1 hoch — beim ersten Auftreten ist count[$1] undefiniert, wird aber implizit als 0 behandelt und auf 1 erhöht. Im END-Block iteriert for (k in count) über alle Schlüssel.
awk '{ips[$1]++} END {for (ip in ips) print ips[ip], ip}' access.log | sort -rn | head -20Die Iterations-Reihenfolge ist nicht garantiert — awk nutzt intern eine Hashtabelle. Wer sortiert ausgeben will, leitet die Ausgabe an sort weiter (siehe Beispiel oben). gawk kennt zusätzlich PROCINFO["sorted_in"], mit dem sich for (k in arr) direkt sortiert iterieren lässt.
Praxis-Patterns
Die Einzeiler, die im Alltag immer wieder gebraucht werden — als Vorlage zum Anpassen.
awk '{s+=$2} END{print s}' werte.txtawk -F',' '{print $3}' daten.csvawk '{count[$1]++} END {for (k in count) print count[k], k}' log | sort -rnawk '{s+=$1; n++} END {print s/n}' zahlen.txtawk '$3 > 1000 {print $1, $3}' werte.txtawk -F: 'BEGIN{OFS="|"} {print $1, $7}' /etc/passwdawk 'NR==FNR{a[$1]=1; next} $2 in a' liste.txt daten.txtDas letzte Pattern ist ein Klassiker: Im ersten Durchlauf (NR==FNR — globale Zeilennummer gleich Datei-Zeilennummer, also erste Datei) wird ein Lookup-Set aufgebaut. next springt zur nächsten Zeile, ohne weitere Regeln zu prüfen. Sobald die zweite Datei beginnt, ist NR > FNR und nur die zweite Regel greift: gibt die Zeile aus, wenn Spalte 2 im Set steht.
awk '{printf "%-20s %10.2f\n", $1, $2}' werte.txtStolperfallen
Default-FS ist Whitespace mit Sonderverhalten
Der Default-Field-Separator ist nicht einfach ein Leerzeichen, sondern “Whitespace mit Speziallogik”: mehrere Leerzeichen oder Tabs zählen als ein Trenner, führende und abschließende Whitespaces werden ignoriert. Sobald man -F',' oder -F':' setzt, gilt diese Magie nicht mehr — zwei Kommas hintereinander erzeugen ein leeres Feld, führendes Komma erzeugt ein leeres $1. Beim Wechsel von Default-FS auf einen Zeichen-FS ändert sich also das Feld-Modell.
print mit Komma vs. ohne Komma
print "x" "y" gibt xy aus — Strings werden ohne Komma einfach konkateniert. print "x", "y" dagegen baut eine OFS-getrennte Liste, also x y mit Default-OFS. Wer print $1 $2 schreibt, bekommt die Felder zusammengeklebt; print $1, $2 setzt das OFS dazwischen. Diese stille Bedeutungsverschiebung ist eine der häufigsten Anfänger-Quellen für kaputte Ausgaben.
Variablen brauchen kein Dollarzeichen — nur Felder
In awk-Skripten ist name = "Linus"; print name korrekt — kein $ vor name. Das $ referenziert ausschließlich Felder: $1 ist Feld 1, $NF ist das letzte Feld, $(i+1) ist das Feld an der Position i+1. Wer aus Shell-Gewohnheit $name schreibt, erhält das Feld an Position name — und da name als String oder 0 interpretiert wird, ist $name gleich $0, also die ganze Zeile. Kein Fehler, aber auch nicht gemeint.
gsub modifiziert $0 als Side-Effect
gsub(/foo/, "bar") ohne dritten Parameter operiert auf $0 — und damit ändert sich nicht nur der String, sondern auch die Felder $1, $2, … werden neu zerlegt. awk '/foo/ {gsub(/foo/, "bar"); print}' druckt die modifizierte Zeile, was meistens gewollt ist. Aber eine spätere Regel sieht eine andere Zeile als das Original — was bei mehrstufigen Skripten überraschen kann. Wer nur ersetzen, aber nicht den Record verändern will, nimmt eine eigene Variable: s = $0; gsub(/foo/, "bar", s).
Float-Vergleich mit == ist gefährlich
if ($1 == 0.1 + 0.2) ... schlägt fehl — awk rechnet wie C in IEEE-754-Floats, und 0.1 + 0.2 ist nicht exakt 0.3. Für Geld- oder Vergleichswerte entweder mit Toleranz arbeiten (if ((a-b)^2 < 1e-9)) oder die Werte als Integer-Cents führen. Für Ausgabe immer printf "%.2f" verwenden, sonst druckt awk 0.30000000000000004 und ähnliche Schönheiten.
GNU-Extensions brechen auf macOS BSD-awk
length(arr) (Anzahl der Schlüssel im Array), gensub, PROCINFO, asort, asorti, strftime, systime und einige andere sind GNU-spezifisch. Auf macOS oder FreeBSD bricht ein Skript, das diese nutzt, mit “syntax error” oder unerwartetem Verhalten ab. Wer portable Skripte schreibt, beschränkt sich auf POSIX-awk — oder installiert via Homebrew gawk und ruft das Skript explizit damit auf.
Single-Quotes innerhalb des Skripts sind ein Krampf
Das awk-Skript steht typischerweise in einfachen Quotes — awk '...'. Will man im Skript selbst ein einfaches Anführungszeichen nutzen, muss man die Shell-Quotes brechen: awk 'BEGIN{print "it'\''s"}'. Sauberer ist die -v-Variante: awk -v q="'" 'BEGIN{print "it" q "s"}' — Variablen werden mit -v name=wert von außen reingegeben und verhalten sich wie normale awk-Variablen.
awk vs. perl vs. python — Komplexität ist die Grenze
Für Einzeiler und einfache Spalten-Logik ist awk unschlagbar kompakt. Sobald aber JSON, reguläre Ausdrücke mit Backreferences, Datei-Joins über mehrere Dimensionen, externe HTTP-Requests oder mathematische Bibliotheken ins Spiel kommen, lohnt sich der Wechsel zu perl, python oder ruby. Faustregel: wenn das awk-Skript länger als 20 Zeilen wird, lieber portieren — die Lesbarkeit leidet schneller als bei Sprachen mit klassischer Struktur.
awk parst KEIN quoted CSV
Echte CSV-Dateien können Felder in Anführungszeichen enthalten, in denen Kommas vorkommen: "Smith, John",42,"New York". awk -F',' zerlegt das in fünf Felder, nicht in drei. Für korrektes CSV-Parsing braucht es spezialisierte Werkzeuge wie csvkit (csvcut, csvgrep), mlr (Miller) oder xsv. awk ist ein Tool für einfache, klar getrennte Spaltenformate — für alles, was Quoting, Escaping oder mehrzeilige Felder kennt, gibt es bessere Optionen.
Weiterführende Ressourcen
Externe Quellen
- awk(1) – Manpage (man7.org) — POSIX-awk Referenz
- GNU AWK User’s Guide — Das vollständige
gawk-Handbuch mit allen Erweiterungen - Arch Wiki: Awk — Kompakter Einstieg und praktische Beispiele
- The AWK Programming Language (Aho/Weinberger/Kernighan) — Das Originalbuch der Sprachschoepfer, 2. Auflage 2024
- Miller (mlr) – Like awk for structured data — Moderne Alternative für CSV, TSV und JSON
Verwandte Artikel
- sed – Stream-Editor — Zeilenbasierte Substitution als Partner zu
awk - grep – Zeilen filtern — Reine Pattern-Suche ohne Action
- cut – Spalten ausschneiden — Schlankere Variante für reines Spalten-Picking
- sort – Zeilen sortieren — Klassischer Nachfolger für
awk-Häufigkeitsausgaben - uniq – Duplikate zählen — Ergänzt
awk-Counts mitsort | uniq -c