awk — Feldbasierte Textverarbeitung und Auswertung

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

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.

Grundlagen

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

awk '{print}' data.txt

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

awk '{print $0}' data.txt

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

awk '{print $1}' access.log

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

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

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

awk '{print $NF}' access.log

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

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).

awk 'NR==5' data.txt

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

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

Feldtrenner

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

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

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

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

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

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

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

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

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

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.

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

Mustererkennung

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

awk '/ERROR/' log.txt

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

awk '!/^#/' config.ini

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

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

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

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

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

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

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

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

Bedingungen & Vergleiche

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

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

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

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

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

awk '$5 > 1000' data.txt

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

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

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

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

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

awk 'NF > 0' messy.txt

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

awk 'NF == 4' data.txt

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

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.

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.

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.

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.

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

Arithmetik & Aggregation

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

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

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

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.

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.

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).

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).

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.

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

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

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

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

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

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

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

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

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

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

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.

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.

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.

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.

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

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

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.

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.

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.

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

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

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.

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

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

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).

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

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

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.

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.

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).

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.

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

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

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.

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

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

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

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

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.

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.

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).

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).

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.

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

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

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

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.

Verwandte Kommandos

  • sed – Stream-Editor zum Ersetzen und für zeilenweise Änderungen
  • grep – schnelle Mustersuche, um Zeilen für awk vorzufiltern
  • cut – leichtgewichtige Feldextraktion für einfache Spaltenaufgaben