|
Grundzüge der Sprache
ProgrammablaufIm Prinzip sieht jedes awk-Programm folgendermaßen aus:Bedingung1 { Aktion1 } Bedingung2 { Aktion2 } Bedingung3 { Aktion3 } ... Bedingungn { Aktionn }
Als Bedingung wird meist ein Suchmuster (pattern) oder regulärer Ausdruck
angegeben.
Aktionen sind immer in geschweifte Klammern eingeschlossen, wobei die öffnende
Klammer immer in der gleichen Zeile stehen muß wie das Pattern. Mehrere
Anweisungen werden durch Strichpunkt getrennt. Die Aktion wird in einer
C-ähnlichen Sprache formuliert. Der Aktionsteil darf sich auch auch
über mehrere Zeilen erstrecken. Im übrigen sind awk-Programme frei
formatierbar (unter Berücksichtigung der obigen Einschränkungen).
In einer Programmzeile kann entweder die Bedingung oder der Aktionsteil
weggelassen werden. Fehlt die Bedingung, wird die Aktion immer ausgeführt.
Fehlt die Aktion, wird die Zeile komplett ausgegeben.
- 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 zuerst und einmalig ein eventuell vorhandener BEGIN-Block
abgearbeitet.
Dieser Block umfaßt die Anweisungen, die mit der speziellen Bedingung
BEGIN angegeben wurden. Hier kann man z. B. Variable initialisieren.
Die Kommandozeilenoption im letzten Beispiel hätte man umgehen
können, indem vor Ausführung der Kommandos der interne
Feldseparator ("FS") auf den Doppelpunkt gesetzt worden wäre.
Eine solche "Initialisierung" ist die typische Aufgabe des BEGIN-Musters:
awk 'BEGIN {FS = ":"} {print NR,$1}' /etc/passwd
1 root
2 bin
3 daemon
4 lp
5 news
...
- Wird ein awk-Programm ausgeführt, so läuft
eine - im Programm nicht aufgeführte - äußere Schleife ab,
die sequentiell alle Zeilen der zu verarbeitenden Eingabedatei liest und dabei
jede Eingabezeile der Reihe nach mit allen aufgeführten Bedingungen
vergleicht. Ist eine Bedingung erfüllt, so wird die zugehörige
Aktion ausgeführt.
awk zerlegt eine Eingabezeile in Abhängigkeit vom
Wert des Feldtrennzeichens FS (eine der
awk-Standard-Variablen; siehe dazu 9.3.3) in
einzelne Felder, die mit $1, $2, ..., $(NF-1) bezeichnet
werden. NF ist eine andere awk-Standard-Variable, in
der die Anzahl der Felder der Eingabezeile gespeichert wird. Auf die gesamte
Eingabezeile kann mit $0 zugegriffen werden.
- Wenn alle Eingabezeilen verarbeitet sind, werden einmaling die Anweisungen im
END-Block abgearbeitet. Der END-Block ist durch das
spezielle Suchmuster END gekennzeichnet. Hier werden häufig Summen
ausgegeben.
Außerdem gibt es die Möglichkeit, Funktionen zu definieren:
function Name(Parameterliste) { Anweisungen }
$1, $2, $3 usw. sind Zeichenketten und können dementsprechend
im Aktionsteil manipuliert und verwendet werden.
Mit diesen Vorkenntnissen sollte die Funktionsweise des ersten Programms leicht
nachvollziehbar sein; es zählt einfach nur die Zeilen der Eingabe und gibt
das Resultat aus:
BEGIN {
print "Zählen von Eingabezeilen";
zaehler = 0
}
{ zaehler++ }
END { print "Ergebnis: " zaehler }
Ein weiteres einfaches Beispiel: Gegeben sei eine Datei, die Zeilen der Art
...
Emil Hofer 23.08.1960 1234 175 cm
Karl Müller 29.02.1957 1236 160 cm
...
mit den Angaben "Vorname", "Nachname", "Geburtsdatum",
"Nebenstellen-Telefonnummer" und "Gewicht" enthält.
Es soll eine Ausgabedatei generiert werden, die
nur noch Geburtsdatum und Vorname (in dieser Reihenfolge)
enthält. awk kennt folgenden AUsgabefunktionen:
- print gibt $0 auf stdout aus (entspricht print $0).
- print ausdruck1, ausdruck2, ...
gibt die Ausdrücke in der angegebenen Reihenfolge durch OFS getrennt auf
stdout aus. Abschließend wird ORS ausgegeben.
print ausdruck1 ausdruck2 ... (ohne Komma!) bewirkt Ausgabe ohne
Trennzeichen.
- printf(format, ausdruck1, ausdruck2,...) gibt
die Ausdrücke gemäß dem Formatstring aus (siehe unten).
Damit kann das erste awk-Programm formuliert werden, was das Gewünschte
leistet:
{print $3, $1}
Da ein Bedingungsteil nicht vorhanden ist, wird die aufgeführte Aktion
unabhängig von Bedingungen für alle Eingabezeilen ausgeführt:
Mitttels der awk-Standard-Funktion print wird der Inhalt der
Felder $3 und $1 in einem Standard-Format ausgegeben.
Das folgende Beispiel druckt eine etwas schöner formatierte Liste aus
der /etc/passwd, wobei die C-ähnliche awk-Standard-Funktion printf
verwendet wird:
BEGIN {
FS=":";
print "-------------------------------------------------------------------";
printf "%-15s %-30s %s\n", "user-id", "Name", "Home";
print "-------------------------------------------------------------------";
}
{printf "%-15s %-30s %s\n", $1, $5, $6}
In obigen Beispielen ist die Aktion von keiner Bedingung abhängig. Als
Bedingung können jedoch ohne weiteres Vergleiche und logische
Ausdrücke angegeben werden, wie im folgenden Beispiel gezeigt
wird:
$4>170 && $6<=80 {print $0}
Angewendet auf die obige Eingabedatei bedeutet das, daß nur noch diejenigen
Eingabezeilen ($0) aufgelistet werden, für die Größe>170
($4>170) und (&&) Gewicht<=80 ($6<=80) gilt.
Bedingungen (Muster, Patterns)
Als häufigste Bedingung werden in awk wohl die von anderen UNIX-Programmen her
bekannten Zeichenkettenmuster in Form regulärer Ausdrücke verwendet.
Dazu zwei Beispiele:
/M[ea][iy]e?r/ {print $2, $3}
Als Bedingung ist hier ein regulärer Ausdruck aufgeführt, mit dem
alle Eingabezeilen erkannt werden, die den Namen "Meier" (mit möglichen
Varianten wie "Mayer", "Maier", "Meyr", "Meir", "Mayr" usw.) enthalten
(Das Fragezeichen im regulären Ausdruck deutet an, daß das unmittelbar
davor aufgeführte Element auch entfallen kann).
Für die betreffenden Zeilen wird dann der Inhalt der Felder $2 und $3
ausgegeben.
$5 !~ /^[0-9][0-9][0-9]$/ {print $1, $2, $5}
Mit Hilfe der hier verwendeten Bedingung kann überprüft werden, ob das
Eingabefeld $5 (Körpergröße der Datei aus dem ersten Beispiel)
einer Eingabezeile eine für ein bestimmtes Problem korrekt
gebildete Zahl enthält. Genauer gesagt, es wird getestett, ob ein angegebenes
Muster nicht (!~) auf das Eingabefeld $5 "paßt".
Ist das der Fall, werden die Felder $1, $2 und $5 der betreffenden Zeile ausgegeben.
Das Muster selbst beschreibt eine Zeichenkette, die aus drei Ziffern besteht.
In den bisherigen Programmbeispielen wurden die awk-Standard-Funktionen
print und printf verwendet. Eine fast ebenso häufig
eingesetzte Funktion ist gsub, mit der Zeichenketten in einer Zeile
gegen andere ausgetauscht werden können. Dazu ein Beispiel:
/ä/ {gsub(/ä/,"ä")}
/Ä/ {gsub(/Ä/,"Ä")}
/ö/ {gsub(/ö/,"ö")}
/Ö/ {gsub(/Ö/,"Ö")}
/ü/ {gsub(/ü/,"ü")}
/Ü/ {gsub(/Ü/,"Ü")}
/ß/ {gsub(/ß/,"ß")}
{print}
Mit Hilfe der in den Bedingungen angegebenen Muster für die deutschen Umlaute
und das scharfe S und der awk-Funktion gsub werden in den betreffenden
Zeilen diese Zeichen gegen die entsprechenden HTML-Umschreibungen ausgetauscht.
Die letzte Programmzeile ist notwendig, damit das Ergebnis der vorgenommenen
Umsetzungen auch die Standardausgabe ausgegeben wird.
Das folgende Beispiel zeigt ein Mini-Programm in der Kommandozeile:
awk ' {printf("%s-%4d %s\n", FILENAME, FNR, $0) }' eingabe*
Es werden die Zeilen aller Dateien, deren Name mit "eingabe" beginnt,
numeriert und mit dem Dateinamen auf der Standardausgabe aufgelistet.
Umbenennen von Dateien (append ".new" to "files_list"):
ls files_list | awk '{print "mv "$1" "$1".new"}' | sh
|
|
|