Praktisch und nützlich: AWK

Programmierhappen für Zwischendurch

Ein Unix-Rechner erschlägt den Anwender förmlich mit kleinen Helferlein, die ihm so gerne zu Diensten wären. Leider lassen sie sich nicht immer ganz problemlos bedienen. Die Textbearbeitungssprache AWK ist ein typisches Beispiel.

Wenn fortgeschrittene Linuxer Probleme lösen, greifen sie oft auf Skriptsprachen zurück: auf die Shell, auf Perl oder AWK. Während Shell- und Perl-Skripte einen hohen Bekanntheitsgrad haben, fragt sich der Uneingeweihte: "Was ist AWK?"

Die Abkürzung steht für die drei Autoren der Sprache: Alfred Aho, Peter Weinberger und Brian Kernighan. AWK liest und bearbeitet textbasierte Dateien. Zwar ist der Interpreter relativ flexibel einsetzbar, seine größte Stärke spielt er jedoch in einem ganz bestimmten Umfeld aus: bei Dateien, deren Zeilen Informationen enthalten, die nach einem vorgegebenen, gleichförmigen Muster aufgebaut sind. Dabei lassen sich Begriffe wie "Zeile" oder "gleichförmig" recht dehnbar auslegen: AWK arbeitet gerne auch mit ganzen Absätzen und sucht sich seine Daten aus komplexen Strukturen heraus.

Der Einstieg ist relativ einfach: Ein AWK-"Programm" besteht aus einer oder mehreren Einheiten. Jede davon enthält einen Vergleichsausdruck sowie einen Befehlsblock. Der Interpreter liest nun die Datei mit Rohdaten Zeile für Zeile (oder Datensatz für Datensatz) ein. Wenn ein Vergleichsausdruck auf eine Zeile passt, führt AWK den zugehörigen Befehlsblock aus.

Eine passende Datensammlung sollte aus purem Text bestehen, wahlweise in ASCII oder in Ihrem bevorzugten Zeichensatz. Typisch sind tabulatorgetrennte Tabellen wie in Listing 1. Doch prinzipiell ist jedes beliebige Trennzeichen zwischen den Feldern erlaubt, zum Beispiel auch ein Komma. AWK erlaubt im Gegensatz zu Perl sogar reguläre Ausdrücke als "Trennausdruck"! Wie heißt es in der Manpage perlvar(1) so schön (und frei übersetzt): "An einer Stelle muss AWK ja besser sein :-)"

Listing 1

Datenquelle

handys.tsv
Handy   Preis   Gewicht
N6310i  419     111
S45i    249     93
T68i    565     84

Erste Schritte

Am häufigsten benutzt man den Interpreter zu ganz einfachen Zwecken wie der Ausgabe der ersten Spalte aus Listing 1:

$ awk '{print $1}' handys.tsv
Handy
N6310i
S45i
T68i

Das "Programm" steht zwischen den beiden Apostrophen. Es enthält eine einzige Einheit, bestehend aus einem Vergleichsausdruck und einem Befehlsblock. Letzterer steht in geschweiften Klammern – hier ist es ein einziges Kommando, print $1, das das erste Feld der gelesenen Zeile ausgibt.

Passt eine Eingabezeile auf den Vergleichsausdruck, wird sie in Felder zerlegt, und zwar von eins an aufsteigend durchnummeriert. Die erste Zeile von Listing 1 beispielsweise zerfällt in drei Felder, $1 = "Handy", $2 = "Preis" und $3 = "Gewicht". Falls Sie sie einmal brauchen, finden Sie die gesamte, unzerteilte Eingabezeile in der Variablen $0 wieder.

Doch wo ist in unserem ersten Beispiel der Vergleichsausdruck? Er ist leer, und das bedeutet: Der zugehörige Befehlsblock wird auf jede Zeile der Datenquelle angewandt.

Weder Programm noch Daten müssen sich übrigens je auf ein einziges Argument beschränken. Sie können mehrere Programmfragmente und auch Dateien, die AWK-Befehle enthalten, in beliebiger Folge angeben. Ebenso dürfen Sie mehrere Datenfiles angeben, die dann einfach nacheinander eingelesen werden. Fehlen Angaben zu Datenquellen an der Kommandozeile, liest AWK einfach die Standardeingabe stdin.

Wer klopft an?

Noch ein Beispiel gefällig? Wir könnten die ISDN-Meldungen des Kernels auswerten und darüber herausfinden, wer bei uns angerufen hat. Wenn ein Anruf eingeht (und der Computer ihn nicht entgegennimmt), produziert Linux im Syslog etwa die Meldungen aus Listing 2 (sie variieren vermutlich von Version zu Version geringfügig).

Listing 2

Unbeantwortete ISDN-Anrufe im Syslog

[…]
Sep 22 11:30:21 nathan kernel: isdn_tty: call from 0 -> 9654321 ignored
Sep 22 11:42:39 nathan kernel: isdn_net: call from 891234567,1,0 -> 9654321
Sep 22 11:42:39 nathan kernel: isdn_net: Service-Indicator not 7, ignored
Sep 22 11:42:39 nathan kernel: isdn_tty: call from 891234567 -> 9654321 ignored
[…]

Dabei interessiert uns vor allem die erste und die letzte Zeile. Mit AWK suchen wir die Meldung über diese und die übrigen nicht abgenommenen Gespräche folgendermaßen heraus:

awk '/kernel.*call from.*ignored/ {print $0}' /var/log/*messages*

Als Vergleichsausdruck kommt hier ein regulärer Ausdruck (zwischen den Schrägstrichen) zum Einsatz. Er passt auf alle Zeilen, die nacheinander die Textfolgen kernel, call from und ignored enthalten; das sind Message 1 und 4 in Listing 2. Diese druckt print $0 komplett aus.

Soweit wären wir mit einer einfachen Suche mit grep wohl auch gekommen. Aber mit AWK lässt sich das beliebig verfeinern. Der nächste Befehl gibt lediglich Datum und Uhrzeit sowie die Rufnummer des Anrufers aus:

$ awk '/kernel.*call from.*ignored/ {printf "%s %02d %s 0%s\n",$1,$2,$3,$9}' /var/log/*messages*
Sep 22 11:30:21 00
Sep 22 11:42:39 0891234567

Damit es nicht langweilig wird, benutzen wir im Befehlsblock diesmal printf statt print. Während letzteres ganz ähnlich wie echo in der Shell funktioniert, bietet printf die gewohnte Funktionalität der entsprechenden C-Routine: Als erstes Argument verlangt es einen Format-String, der Platzhalter für die auszugebenden Variablen enthält und deren Formatierung festlegt.

Ein solcher Platzhalter beginnt immer mit dem Prozentzeichen %. Danach steht ein Buchstabe, der das Format der auszugebenden Variablen enthält, in unserem Beispiel z. B. s für einen String oder d für eine (ganzzahlige) Dezimalzahl. Wichtige Alternativen sind %e, %f und %g für Fließkommazahlen in verschiedenen Darstellungsweisen oder %x für eine Hexadezimalzahl. Wollen Sie tatsächlich ein Prozentzeichen ausgeben, verdoppeln Sie es: %%.

Zwischen % und der Formatangabe dürfen noch zusätzliche Zeichen stehen, die das gewünschte Format genauer bezeichnen. In unserem Beispiel haben wir %02d geschrieben. Die Zahl 2 steht für die Feldbreite, d. h., selbst wenn die Zahl (in diesem Fall der Tag) nur eine Stelle hat, sollen zwei Stellen ausgegeben werden. AWK würde normalerweise ein Leerzeichen voranstellen, aber wegen der zusätzlich angegebenen 0 füllt es die gewünschte Feldbreite mit Nullen auf. Für den 7. September erhalten wir aus $1 und $2 also Sep 07.

Wenn Sie die Feldbreite einer Fließkommazahl festlegen wollen, benutzen Sie zwei Zahlen: eine für die gesamte Feldbreite (einschließlich Punkt bzw. Komma, Exponent und/oder Nachkommastellen) und eine für den Anteil nach dem Fließkomma (oder Dezimalpunkt, je nachdem).

Die Telefonnummer des Anrufers aus $9 ergänzt der Format-String um eine führende 0, um das gewohnte Telefonbuch-Aussehen zu erhalten. Das \n am Ende sorgt für einen Zeilenumbruch, der bei print noch automatisch eingefügt wurde. Auf die Formatierungsangaben folgt mit $1,$2,$3,$9 die Auswahl der Daten.

Sie sehen den kleinen Schönheitsfehler: Wenn eine Rufnummer nicht übertragen wurde, schreibt der Kernel einfach eine 0 in die Logdatei. Zusammen mit der angehängten Null ergibt das dann den seltsamen Anrufer 00. Doch AWK erlaubt beliebig komplexe Befehle, so dass wir dieses Problemchen lösen können (Listing 3).

Listing 3

Unbekannte Anrufer benennen

$ awk '/kernel.*call from.*ignored/ {printf "%s %02d %s %s\n",$1,$2,$3,$9==0 ? "unbekannter Anrufer" : "0"$9}' /var/log/*messages*
Sep 22 11:30:21 unbekannter Anrufer
Sep 22 11:42:39 0891234567

Statt des lapidaren $9 steht diesmal ein ?:-Ausdruck. Vor dem Fragezeichen enthält dieser eine Bedingung. Ist sie erfüllt, gilt der Abschnitt zwischen Fragezeichen und Doppelpunkt, ansonsten der Abschnitt vom Doppelpunkt bis zum Ende:

$9 == 0
   ? "unbekannter Anrufer"
   : "0"$9

Zu deutsch: "Wenn Variable $9 gleich null ist, dann drucke unbekannter Anrufer, ansonsten schreibe eine 0 plus den Inhalt von $9." Wer C kennt, weiß das alles schon, lediglich der Umgang mit Strings ist in AWK etwas einfacher.

LinuxCommunity kaufen

Einzelne Ausgabe
 
Abonnements
 
TABLET & SMARTPHONE APPS
Bald erhältlich
Get it on Google Play

Deutschland

Ähnliche Artikel

  • Reguläre Ausdrücke
    Regulären Ausdrücken begegnet man auf Unix-Systemen an allen Ecken und Enden. Doch was genau hat es damit auf sich, und wie nutzt man sie?
  • Awk – Werkzeug und Skriptsprache
    Unter Linux ist die Bandbreite der Verwendung von Textdateien groß: Systemkonfiguration, Systemüberwachung und Datenaustausch. Mit Awk steht ein mächtiges Werkzeug zur Verarbeitung und gezielten Veränderung dieser Dateien zur Verfügung.
  • Zu Befehl: bash, bc
    Es muss nicht immer ein grafischer Taschenrechner wie xcalc oder KCalc sein – auch die Bash beherrscht einfache arithmetische Operationen, und für die fortgeschrittenen Mathematiker gibt's bc.
  • Gut gefiltert
    Zu den häufigsten Aufgaben bei der Arbeit am Rechner zählt das Durchstöbern von Texten nach Suchmustern. Icgrep bietet hier eine moderne, parallel arbeitende und Unicode-fähige Alternative zum klassischen Grep.
  • The Answer Girl
    Solange man online ist, halten sich die Sprachprobleme in Grenzen: Web-Wörterbücher wie dict.leo.org helfen in meistens akzeptabler Geschwindigkeit über die Hürden des fehlenden (Englisch-) Wortschatzes hinweg. Doch wehe, man ist weder mit Standleitung noch Flatrate gesegnet: Schon ärgert man sich, das Regal mit den papiernen Wörterbüchern am anderen Ende des Raums aufgestellt zu haben.
Kommentare

Infos zur Publikation

LU 12/2017: Perfekte Videos

Digitale Ausgabe: Preis € 5,95
(inkl. 19% MwSt.)

LinuxUser erscheint monatlich und kostet 5,95 Euro (mit DVD 8,50 Euro). Weitere Infos zum Heft finden Sie auf der Homepage.

Das Jahresabo kostet ab 86,70 Euro. Details dazu finden Sie im Computec-Shop. Im Probeabo erhalten Sie zudem drei Ausgaben zum reduzierten Preis.

Bei Google Play finden Sie digitale Ausgaben für Tablet & Smartphone.

HINWEIS ZU PAYPAL: Die Zahlung ist ohne eigenes Paypal-Konto ganz einfach per Kreditkarte oder Lastschrift möglich!

Stellenmarkt

Aktuelle Fragen

Installation Linux mint auf stick
Reiner Schulz, 10.12.2017 17:34, 0 Antworten
Hallo, ich hab ein ISO-image mit Linux Mint auf einem Stick untergebracht Jetzt kann ich auch...
Canon Maxify 2750 oder ähnlicher Drucker
Hannes Richert, 05.12.2017 20:14, 4 Antworten
Hallo, leider hat Canon mich weiterverwiesen, weil sie Linux nicht supporten.. deshalb hier die...
Ubuntu Server
Steffen Seidler, 05.12.2017 12:10, 1 Antworten
Hallo! Hat jemand eine gute Anleitung für mich, wie ich Ubuntu Server einrichte? Habe bisher...
Tinte sparen bei neuem Drucker
Lars Schmitt, 30.11.2017 17:43, 2 Antworten
Hi Leute, ich habe mir Anfang diesen Monats einen Tintenstrahldrucker angeschafft, der auch su...
Für Linux programmieren
Alexander Kramer, 25.11.2017 08:47, 3 Antworten
Ich habe einen Zufallsgenerator entworfen und bereits in c++ programmiert. Ich möchte den Zufalls...