Home / LinuxUser / 2002 / 10 / Praktisch und nützlich: AWK

Newsletter abonnieren

Lies uns auf...

Folge LinuxCommunity auf Twitter

Top-Beiträge

War doch klar...
(243 Punkte bei 15 Stimmen)
Re: War doch klar...
(179 Punkte bei 5 Stimmen)
Re: Skype für 64-Bit-Prozessor u. Suse 12.1
(161 Punkte bei 4 Stimmen)
Kubuntu verliert Finanzierung
(130 Punkte bei 4 Stimmen)
Offen fürs Geschäft
(80 Punkte bei 4 Stimmen)

Heftarchiv

LinuxUser Heftarchiv

EasyLinux Heftarchiv

Ubuntu User Heftarchiv

Ubuntu User Heftarchiv

Partner-Links:

Shopping
Topsuche
 
Yatego Deutschlands größte Shoppingmall. 10000 Shops,
3.5 Mio Artikel. Alle Bestseller, Servertechnik und Technik Themenwelten.

Notebooks und Netzwerkhardware bei Mercateo günstig kaufen.
Internet Telefonie mit VoIP Telefonen von Gigaset
Das B2B Portal www.Linx.de informiert über Produkte und Dienstleistungen.
Günstige Digitalkameras finden Sie im Preisvergleich.

Programmierhappen für Zwischendurch

Praktisch und nützlich: AWK

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

Einem Freund empfehlen    Druckansicht Bookmark and Share
Kommentare

1001 Hits
Wertung: 55 Punkte (2 Stimmen)

Schlecht Gut

Infos zur Publikation

Infos zur Publikation

LinuxUser 03/2012

Aktuelle Ausgabe kaufen:

Heft bestellen Heft als PDF kaufen

LinuxUser erscheint monatlich und kostet in der Nomedia-Ausgabe EUR 5,50 und mit DVD EUR 8,50. Weitere Informationen zum Heft finden Sie auf der LinuxUser-Homepage.

Im LinuxUser-Probeabo erhalten Sie drei Ausgaben für 3 Euro. Das Jahresabo (ab EUR 56,10) können Sie im LNM-Shop bestellen.

Tipp der Woche

Duden Korrektor unter 64-Bit
Duden Korrektor unter 64-Bit
Tim Schürmann, 06.02.2012 10:36, 0 Kommentare

Der Duden Korrektor bietet eine äußerst nützliche Rechtschreib- und Grammatikkorrektur für LibreOffice und bringt in der aktuellen Version 8 e...

Aktuelle Fragen

N24 Stick (Huawei E173) und Ubuntu 11.04
Patrick Obenauer, 11.02.2012 11:54, 0 Antworten
Hallo zusammen! Ich benutze einen alten Laptop, der mit Ubuntu 11.04 flott und problemlos läuft....
Wie kann man beim Einsatz von Compiz die Fenster-Dekoration einstellen?
GoaSkin , 10.02.2012 20:12, 0 Antworten
Hallo, ich nutze Linux Mint mit dem Gnome-Derivat Mate. Da die Distribution Compiz nicht autom...
rndc reload zone - failed bad zone
Ludwig jun. B., 06.02.2012 16:08, 2 Antworten
Schönen guten Tag, ich habe folgendes Problem. Immer wenn ich folgendes Kommando ausführen bek...
Skype für 64-Bit-Prozessor u. Suse 12.1
Klaus Sigerist, 05.02.2012 11:39, 3 Antworten
Hallo Gemeinde! Ich bin nur ein einfacher Nutzer und habe Probleme mit der Installation von Skyp...
8! Anfängerfrage :) Wie finde ich in Ubuntu die Datenträger (Bild, Text)
samuel leusam, 04.02.2012 15:53, 2 Antworten
Ich habe neu Ubuntu. Wenn ich die SD Karte im Laptop einstecke, erkennt er sie und gibt ihr den N...