awk ist eine Sprache zur Verarbeitung von Textdateien. Die Bezeichnung awk setzt sich einfach aus den Anfangsbuchstaben der Nachnamen der Erfinder dieser Sprache, Aho, Kernighan und Weinberger, zusammen.
Unter Linux wird die GNU Implementierung gawk benutzt, die außer allen im POSIX-Standard vorgesehenen Features auch die Erweiterungen aus SVR4 unterstützt.
Der awk zählt zu den grundsätzlichen Tools, die auf jedem UNIX-System verfügbar sein sollten. Er wird recht oft von anderen Programmen benutzt und sollte deshalb auf jeden Fall mit installiert werden.
Die Sprache awk ist recht einfach. Man kann Sie ohne weiteres aus der ziemlich umfangreichen Man-Page erlernen.
Der awk ist ein Interpreter. Im einfachsten Fall ist das auszuführende Script so kurz, daß man es gleich mit auf der Kommandozeile angeben kann:
awk [Optionen] [--] Programmtext Datei ...
Folgendes Beispiel gibt Namen der Benutzer und das jeweilige Home-Verzeichnis aus:
awk -F: '{print $5, $6}' /etc/passwdDabei gibt die Option
-F:an, daß der Doppelpunkt als Trennzeichen zwischen Feldern aufgefaßt werden soll. Das eigentliche awk-Programm besteht aus
{print $1, $6}Die Hochkommas verstecken die im Script enthaltenen Sonderzeichen vor der Shell. Die geschweiften Klammern gehören zum Programm und sind auch wichtig, wie wir später noch sehen werden.
Im awk werden Anweisungen, ähnlich der Shell, durch Semikolon getrennt. Damit kann man auch mehrere Anweisungen auf der Kommandozeile unterbringen. Trotzdem ist die Grenze der Übersichtlichkeit schnell erreicht und man schreibt das awk-Script lieber in eine Datei. Der Programmaufruf sieht dann so aus:
awk [Optionen] -f Programmdatei [--] Datei ...
Die Programmdatei wird dabei entsprechend der Pfadangaben in der Umgebungsvariable AWKPATH gesucht. Ist diese Variable nicht gesetzt, so wird das aktuelle Verzeichnis und anschließend /usr/local/share/awk durchsucht.
Suchmuster { action statements }Außerdem gibt es die Möglichkeit, Funktionen zu definieren:
function name(Parameterliste) { statements }awk liest zunächst das komplette Programm ein und überführt es in eine interne Darstellung, die sich schneller ausführen läßt. Dann wird zunächst ein eventuell vorhandener BEGIN-Block abgearbeitet. Dieser Block umfaßt die Statements, die mit dem speziellen Suchmuster BEGIN angegeben wurden. Hier kann man z.B. Variable initialisieren.
Dann werden alle Dateien in der angegebenen Reihenfolge zeilenweise gelesen. Für jede Zeile wird geprüft, mit welchen Suchmustern diese übereinstimmt. Die für diese Suchmuster angegebenen Aktionen werden ausgeführt.
Wenn alle Eingabezeilen verarbeitet sind, werden die Bestimmungen im END-Block abgearbeitet. Der END-Block ist durch das spezielle Suchmuster END gekennzeichnet. Hier werden häufig Summen ausgegeben.
Das folgende Beispiel druckt eine etwas schöner formatierte Liste aus der /etc/passwd, wobei nur Benutzer aufgeführt werden, die die bash als Login-Shell benutzen:
BEGIN { FS=":"; print "Bash-Benutzer:" print "-------------------------------------------------------------------"; printf "%-15s %-30s %s\n", "user-id", "Name", "Home"; print "-------------------------------------------------------------------"; } /\/bin\/bash/ {printf "%-15s %-30s %s\n", $1, $5, $6}bsp1.awk bsp2.csv
awk verwendet dynamische Variable. Diese brauchen nicht deklariert zu werden und können Strings oder Gleitkommawerte enthalten.
Sätze entsprechen normalerweise Zeilen, sie werden also durch das LF voneinander getrennt. Man kann aber auch durch Setzen der speziellen Variable RS einen anderen Satztrenner festlegen. Wird RS mit einer leeren Zeichenkette belegt, so werden Sätze durch Leerzeilen getrennt.
Beim Lesen eines Satzes wird dieser von awk in Felder zerlegt. Die Trennung erfolgt normalerweise durch Whitespace (Leerzeichen oder Tabulatoren), kann aber durch Setzen der Variable FS anders geregelt werden. Wird FS mit einer leeren Zeichenkette belegt, so wird aus jedem einzelnen Zeichen ein Feld.
Enthalten RS und FS mehr als ein Zeichen, so wird ihr Inhalt als regulärer Ausdruck aufgefaßt. Oft findet man auch awk-Aufrufe folgender Gestalt:
awk -v 'FS=^\"?|\"?,\"?|\"?$' '{print $3, $2}' datei.csvHier wird die Zuweisung der Variable FS auf der Kommandozeile vorgenommen. Der oben angegebene Ausdruck zerlegt CSV-Dateien, wie sie von Excel oder dBase exportiert werden, in einzelne Felder.
Felder werden im Programm durch das Dollarzeichen mit nachgestellter Position im Eingabesatz bezeichnet. Dabei werden die Positionen mit 1 beginnend gezaehlt. $7 bezeichnet also das siebte Feld. Mit $0 erreicht man den gesamten Eingabesatz. Man kann auch Werte an Felder zuweisen. Auch ist es möglich, die Feldposition einer Variable zu entnehmen:
n=5 print $ngibt das fünfte Feld aus.
awk verfügt über einige eingebaute Variable. Die wichtigsten davon sind:
Es existieren weitere spezielle Variable, auf die hier nicht weiter eingegangen werden soll.
awk kennt keine echten Variablentypen, es wird nur mit Strings hantiert. Diese werden allerdings als Zahlen aufgefaßt, wenn das im Zusammenhang sinnvoll ist. Soll die Auswertung als Zahl erzwungen werden, so addiert man eine 0.
Neben den einfachen Strings kennt awk noch assoziative Arrays. Die Indizes eines solchen Arrays sind (im Gegensatz zu C) Strings. Man kann auch mehrdimensionale Arrays verwenden.
Die Anweisungen des awk bestehen aus dem Suchmuster und den in geschweifte Klammern eingeschlossenen Aktionen. Fehlt das Suchmuster, so werden die Aktionen für alle Eingabezeilen durchgeführt. Fehlt die Aktion, so wird die Eingabezeile unverändert ausgegeben. Der folgende awk-Aufruf entspricht einem einfachen grep:
awk '/reg. Ausdruck/' Datei
Das Script kann Kommentare enthalten. Diese beginnen mit dem Zeichen # und erstrecken sich bis zum Zeilenende. Leerzeilen sind zulässig. Ein Statement endet normalerweise am Zeilenende. Um Statements auf der nächsten Zeile fortzusetzen, maskiert man das Zeilenende mit einem Backslash.
Man kann folgende Suchmuster verwenden:
BEGIN und END wurden schon erläutert. Die regulären Ausdrücke entsprechen denen von egrep. Vergleichende Ausdrücke können umfangreicher sein. Man kann z.B. testen, ob bestimmte Felder einem regulären Ausdruck entsprechen. Die Operatoren &&, ||, ! und ? werden in Analogie zu C angewandt (logisches Und, Oder, Negation und wahlweise Ausführung). Durch Klammern kann man die Reihenfolge der Ausführung bestimmen. Zwei durch Komma getrennte Suchmuster ermitteln einen Bereich von Zeilen, wobei die erste vom ersten, die letzte vom zweiten Suchmuster bestimmt wird.
Operator | Bedeutung |
---|---|
(...) | Gruppierung |
$ | Feldreferenz |
++ -- | Inkrement und Dekrement, in postfix- oder präfix-Notation |
^ | Potenzieren |
+ - ! | unäres plus, minus und logische Negation |
* / % | Multiplikation, Division, Modulo-Funktion |
+ - | Addition, Subtraktion |
space | Stringverkettung |
< > <= >= == != | Vergleiche |
~ !~ | Vergleich mit regulären Ausdrücken |
in | Test auf Enthaltensein in einem Array |
&& | Logisches Und |
|| | Logisches Oder |
?: | Bedingter Ausdruck, wie in C |
= += -= *= /= %= ^= | Zuweisung, wie in C |
Die meisten Steueranweisungen haben eine direkte Entsprechung in C:
Anweisung | Bedeutung |
---|---|
close(Datei) | Datei (oder Pipe) schließen |
getline | nächste Zeile in $0 laden |
getline <Datei | Nächste Zeile aus bestimmter Datei lesen |
getline Variable | Nächste Zeile in Variable, statt $0, laden |
getline Variable <Datei | Zeile aus Datei in Variable laden |
next | Nächste Zeile lesen und ab Anfang des Scriptes bearbeiten |
nextfile | Aktuelle Datei schließen und mit nächster fortfahren |
Gibt den aktuellen Satz aus | |
print Ausdrucksliste | Gibt Ergebnis der Ausdrücke aus. |
print Ausdrucksliste >Datei | Schreibt Ergebnis der Ausdrücke in Datei |
printf Format, Ausdrucksliste | Gibt Ergebnisse formatiert aus |
printf Format, Ausdrucksliste >Datei | formatierte Ausgabe in Datei |
system(Befehlszeile) | Führt einen Befehl aus |
fflush([Datei]) | Erzwingt das Schreiben der Puffer |
Andere Dateiumleitungen als > sind ebenfalls erlaubt. >> hängt Daten an eine bestehende Datei an, | schreibt die Daten in eine Pipe.
Das Format für printf stimmt im wesentlichen mit dem für die entsprechende C-Funktion überein.
awk -F: 'match($7,"/bin/bash")' /etc/passwd