Linux Basics - awk Grundlagen
awk - ein mächtiges Linuxtool zur Verarbeitung von Textdaten #
Das Programm awk wurde in den 1970er Jahren bei den Bell Labs entwickelt und ist also schon etwas älter. Der Name des Programms leitet sich dabei von den Namen der drei Entwickler Aho, Weinberger und Kernighan ab. Das Programm selber wurde entwickelt um strukturierte Daten aus Dateien auszulesen und anderweitig auszugeben, beispielsweise zur Erstellung von Reports. Dabei ist awk mittlerweile so komplex dass es rein formal eine vollwertige Programmiersprache darstellt, das keyword hier ist formal denn obwohl man prinzipiell mit awk Programme schreiben könnte ist das tool nicht dafür ausgelegt und awk Programme sind eher als Kuriosität zu betrachten. Da awk mittlerweile ein paar Jahre auf dem Buckel hat, wird das ursprüngliche Programm heute eigentlich nicht mehr verwendet, sondern die meisten Linux Distributionen bringen Weiterentwicklungen von awk mit wie bspw. gawk, mawk oder nawk. Diese sind in der Regel alle miteinander kompatibel, erweitern aber das Grundprogramm um eine Reihe von Funktionen, short cuts und quality-of-life Verbesserungen.
Warum sollte ich awk verwenden? #
Egal wie man es dreht und wendet, awk ist schon ein wenig angestaubt aufgrund seines Alters. Trotzdem ist awk ein unglaublich starkes tool - sofern man sich innerhalb der Grenzen seines Einsatzbereiches bewegt. Sprachen wie Perl oder Python sind mit Sicherheit vielseitiger, aber wenn man “nur” Daten bspw. aus einer Log-Datei extrahieren möchte ist awk eines der besten tools die man nutzen kann da die Skripte relativ kurz sind (oft nur 1-2 Zeilen lang) und awk wesentlich schneller arbeitet als beispielsweise ein Python Skript. Ebenfalls eignet sich awk laut meiner Erfahrung ganz wunderbar zur Formatierung von Output, beispielsweise wenn man das Ergebnis einer SQL Abfrage ein wenig umformatieren und aufhübschen möchte. Ein weiterer Faktor den man nicht unterschätzen darf ist die Tatsache dass awk in praktisch jeder Linux Distribution mitgeliefert wird und man nicht erst noch weitere Softwarepakete installieren muss.
Ein Awk-Programm besteht aus einer Reihe von Muster-Aktion Paaren. Das bedeutet, dass awk eine oder mehrere Dateien zeilenweise durchsucht und mit dem vorgegebenen Muster abgleicht. Wird eine passende Zeile gefunden, so wird die zugewiesene Aktion durchgeführt. Muster können hier beispielsweise durch regular expressions, Vergleichsoperationen auf Zahlen, Zeichenketten, Feldern, Variablen usw. vorgegeben sein.
Awk bietet also durchaus die Möglichkeit auch komplexere Skripte zu schreiben.
Arbeitsweise und Syntax von awk #
awk arbeitet indem es Daten zeilenweise einliest und anhand eines vorgegebenen Delimiters 1 in Felder zerlegt und diese dann ausgibt. Die Funktionsweise ist sed sehr ähnlich, aber erlaubt wesentlich komplexere Konstrukte.
Ein typischer awk Aufruf könnte beispielsweise so aussehen:
awk 'MUSTER { AKTION }' dateiname.txt
Dabei erfolgt der Aufruf von awk mittels des Programmnamens awk, einem sogenannten Muster-Aktionen-Paar und (in aller Regel) einer Datei auf welche die Operationen angewendet werden sollen (awk kann aber natürlich auch mit Daten aus einem Eingabestrom zurechtkommen).
Der Delimiter (Feld-Separator) #
Standardmäßig verwendet AWK einen oder mehrere aufeinanderfolgende Leerzeichen oder Tabs als Feld-Separator.
Man kann den Separator (Delimiter) jedoch frei bestimmen, was für die Analyse von Log-Dateien, die oft durch Doppelpunkte, Kommas oder Semikola getrennt sind, essenziell ist.
Der Feld-Separator wird mit der Option -F definiert:
# Trennt die Eingabe am Doppelpunkt
awk -F':' '{ print $1 }' /etc/passwd
Hierbei steht $1 für das erste Feld (Spalte), $2 für das zweite, und so weiter.
Muster-Aktionen-Paare im Detail #
Wie bereits erwähnt, besteht ein AWK-Programm aus Muster-Aktionen-Paaren. Eine Aktion wird nur ausgeführt, wenn das Muster für die aktuelle Zeile zutrifft. Fehlt das Muster, wird die Aktion auf jede Zeile angewendet. Fehlt die Aktion, wird die gesamte Zeile (print $0) ausgegeben, wenn das Muster zutrifft.
1. Muster: Reguläre Ausdrücke (RegEx) #
Die gebräuchlichste Form des Musters ist der reguläre Ausdruck. Er wird von Schrägstrichen (/) umschlossen.
Beispiel: Fehlermeldungen filtern #
Wenn Ihr eine Log-Datei nach Zeilen durchsuchen möchtet, die das Wort error enthalten, nutzt Ihr einen regulären Ausdruck:
# Durchsucht die gesamte Zeile ($0) nach dem Muster 'error'
awk '/error/ { print $0 }' logfile.txt
Da die Aktion die Standardaktion (print $0) ist, kann man diese sogar weglassen:
awk '/error/' logfile.txt
2. Muster: Vergleichsoperationen auf Feldern #
Hier wird eine Bedingung für den Inhalt oder Wert eines bestimmten Feldes gestellt.
Beispiel: HTTP-Status-Codes filtern #
Um alle Zeilen aus der access.log zu finden, bei denen der HTTP-Status-Code (Feld 9) gleich 404 ist, verwendet Ihr einen numerischen Vergleich:
# Zeigt alle Zeilen mit einem 404-Fehler
awk '$9 == 404 { print $0 }' access.log
3. Muster: BEGIN und END #
Diese beiden Muster sind bspw. für die Erstellung von Reports interessant, da sie Aktionen vor der eigentlichen Verarbeitung und nach Abschluss der Verarbeitung definieren. Dadurch kann man beispielsweise einer Auswertung eine Kopf- und Fußzeile hinzufügen:
awk '
BEGIN {
# Setzt den Output Field Separator (OFS) für schönere Ausgabe
OFS="\t"
# Gibt den Header aus
print "--- Start des Reports ---"
print "IP\tStatus\tLetztes Feld"
print "-------------------------"
}
{
# Hauptaktion: Wird auf jede Zeile angewendet
print $1, $9, $NF
}
END {
# Gibt die Fußzeile aus und meldet, wie viele Zeilen verarbeitet wurden
print "-------------------------"
print "Ende des Reports. Verarbeitete Zeilen: " NR
}' access.log
Felder und Variablen #
AWK definiert beim Einlesen jeder Zeile automatisch einige spezielle Variablen:
| Variable | Beschreibung |
|---|---|
$0 | Die komplette eingelesene Zeile. |
$1, $2, $N | Das erste, zweite oder N-te Feld (die N-te Spalte). |
NF | Die Anzahl der Felder in der aktuellen Zeile (Number of Fields). |
NR | Die Zeilennummer der aktuellen Zeile (Number of the Record). |
FS | Der Feld-Separator (Field Separator). Kann mit -F überschrieben werden. |
Beispiel: Felder filtern und ausgeben #
Angenommen, Sie haben eine Log-Datei (access.log) mit Leerzeichen als Separator, und Sie möchten nur die IP-Adresse (Feld 1) und den HTTP-Status-Code (Feld 9) ausgeben.
# Access.log: 192.168.1.1 - [10/Feb/2023:10:00:00] "GET /index.html" 200 ...
awk '{ print "IP: " $1, " | Status: " $9 }' access.log
# Ausgabe: IP: 192.168.1.1 | Status: 200
Beispiel: Das letzte Feld ausgeben #
In manchen Log-Dateien ändert sich die Anzahl der Felder. Um immer das letzte Feld auszugeben (z.B. eine Fehlermeldung), nutzt man die Variable NF:
# Gibt immer das letzte Feld der Zeile aus
awk '{ print $NF }' logfile.txt
sed und awk arbeiten wunderbar zusammen #
Man kann awk sehr gut mit sed kombinieren. Anbei ein paar Beispiele. Eine kurze sed Einführung gibt es im Artikel zu sed.
Weitere Informationen #
Dieser Artikel kann und soll nur einen groben Überblick geben. Umfangreichere Informationen und eine ganze Liste der vordefinierten Variablen, Parameter etc. findet man entweder lokal in den man und info pages oder aber online.
Als refresher: die man pages ruft man auf über man awk und die info pages über info awk.
Als einfache und gute Alternative kann ich hier allerdings noch das Tool tldr empfehlen, über das ebenfalls nochmal ein Artikel folgen wird.
Fußnoten #
Ein Delimiter kann beispielsweise ein Leerzeichen, Tab, Doppelpunkt, Komma o.ä. sein und in awk frei bestimmt werden. ↩