AWK
oder die Kunst
mit regulären Ausdrücken
zu flirten

Michael Braun, im Dez. 2000

2. aktualisierte Ausgabe

Dies ist eine kurze Einführung in eines der mächtigsten Unix-Tools awk. In diesem Namen haben sich die Autoren Ahoe, Weinberger und Kernighan verewigt. Wenn Sie Fragen oder Anregungen zu diesem Text haben, schreiben Sie mir einfach ein E-Mail.

Mit diesem Text habe ich zwei Dinge verfolgt, zum einen wollte ich aufzuzeigen, wie man mit simplem HTML-Code sauber druckbare Textdokumente erzeugen kann und zum anderen natürlich eines der mächtigsten Tools aus der Unix-Familie darzustellen. Ich selber habe awk fast täglich genutzt und festgestellt, man kann damit (fast) alles lösen und man wird immer schneller. Viel Spaß beim Experimentieren!

Schöne Grüße

Michael Braun (www.net-braun.de)

 

Gliederung

  1. Summary
  2. Die AWK-Syntax
  3. Beispielsammlung
  4. Einfache AWKs

 


 

Summary

Reguläre Ausdrücke

Die Metazeichen in Regulären Ausdrücken

.
Punkt beliebiges Zeichen
*
Stern ein Zeichen kommt keinmal, einmal oder öfters vor
+
Plus Zeichen kommt einmal oder mehrmals vor
?
Fragezeichen Zeichen kommt nicht oder
genau einmal vor
[...]
Set eine Aufzählung von Zeichen, die eine Stelle reprsentieren
[^...]
negiertes Set dito, negiert
^
Circonflex Zeilenanfang
$
Dollar Zeilenende

{n}

{n,m}

Anzahl

Anzahl von, bis

Der beschriebene Ausdruck oder das Zeichen kommt n mal vor

kommt n bis m mal vor

 


grep, sed und awk

awk hat einige Verwandte, die auch gute Dienste leisten können. Viele kennen den guten alten grep und seine Brüder fgrep und egrep. Ein weiteres Mysterium ist das Utility sed. Nicht zu Verwechseln mit SED, der Sozialistischen Einheitspartei Deutschlands, die ihre sog. Wählerschaft hauptsächlich in den Ländern der ehemaligen Deutschen Reichsbahn hatte. Sed steht für stream-editor und ist vom rudimentären Editor ed, abgeleitet.

Einige nützliche sed-Beispiele:

einige grep-Beispiele:

Befehlsübersicht von awk:

#
if
if in
for
for in
while
break
continue
delete
exit
next
print[f]
END
BEGIN

 

Regexp

Ist ein Paket nützlicher Funktionen um in Programmiersprachen wie C, C++, Java oder Perl mit erweiterten Regulären Ausdrücken arbeiten zu können. Die Regulären Ausdrücke sind warscheinlich nicht, oder nur kaum lesbar, aber sie machen die Programme schlank und effizient, denn alles was durch einen Regulären Ausdruck beschrieben werden kann, kann auch automatisch geprüft werden.

In C ist Regexp eine Library mit zugehörigem Header-File. Im Wesentlichen werden dort nur zwei Funktionen benötigt:

Eine zum Beschreiben des Regulären Ausdrucks, die im Hintergrund einen kompletten Parser-Baum aufbaut und eine weitere um einen String gegen den Parserbaum zu prüfen.

 


 

Die AWK-Syntax

Input für das "awk" Kommando

Das awk-Kommando kennt zweierlei Arten von Input. Input-Textfiles und Programminstruktionen. Die Suche und die entsprechenden Aktionen werden Textdateien ausgeführt. Die Dateien werden dabei angegeben durch:

Falls mehrere Dateinamen in der Kommandozeile angegeben sind, werden die Dateien in der genannten Reihenfolge abgearbeitet. Die vom vom Programmierer bereitgestellent Instruktionen steuern die Aktionen des awk-Kommandos. Diese Instruktionen kommen entweder wieder aus der Kommandozeile oder aus der mit der Option -f angegebenen Datei. Werden wiederum mehrere Programmdateien angegeben, werden diese in der Aufzählungsreihenfolge abgearbeitet.

Output für das awk Komando

Das awk-Kommando produziert Output auf drei Arten:

Alle diese Arten der Ausgabe können gleichzeitig auf die selbe Datei angewendet werden. Außerdem erlaubt die Programmiersprache von awk auch eine Redirektion (Umleitung) von Ausgaben.

Dateiverarbeitung mit Sätzen und Feldern (Records und Fields)

Dateien werden auf Folgende Art und Weise verarbeitet

  1. Das awk-Kommando scannt seine Instruktionen und führt jene Befehle aus, die vor dem einlesen der Eingabedatei auszuführen sind.
    Das BEGIN Statement der awk-Programmiersprache erlaubt dem Anwender eine Reihe von Instruktionen anzugeben, die ausgeführt werden bevor der erste Satz aus der Eingabedatei gelesen wurde. Dies ist teilweise nützlich um Variable zu initialisieren.
  2. Ein Satz (eine Zeile) aus der Eingabedatei wird gelesen.
    Ein Record ist ein Satz von Daten, die Durch einen definierten Satztrenner (record seperator) getrennt werden. Der Default-Wert für diesen Satztrenner ist der Zeilenumbruch (new-line character \n ), der aus jeder Zeile der Datei einen eigenen Datensatz macht. Der Satztrenner kann geändert werden, indem die Spezialvariable RS auf einen andere Wert gesetzt wird.
  3. Der Satz wird mit jedem Muster im awk-Script verglichen
    Es ist möglich ein spezifisches Feld aus dem Satz zu vergleichen. In der Regel werden Felder durch sog. white-spaces (Leerzeichen und Tabs) getrennt. Jedes Feld kann durch eine Feldvariable angesprochen werden. Dem ersten Feld im Satz wird die Variable $1 zugewiesen, dem zweiten $2 und so weiter. Der ganze Satz kann unter der Variable $0 angesprochen werden. Der Feldtrenner kann durch den Schalter -F in der Kommandozeile geändert werden oder durch setzen der FS Spezialvariable. Mögliche Werte sind ein Leerzeichen, ein einzelnes Zeichen, oder ein erweiterter regulärer Ausdruck.
  4. Falls der Satz einem Muster entspricht, werden alle damit Verbundenen Aktionen auf diesen Satz ausgeführt.
  5. Nachdem der Satz mit allen vorhandenen Mustern verglichen worden ist, und alle Aktionen ausgeführt worden sind, wird der nächste Satz von der Eingabedatei gelesen. Dies wird solange wiederholt bis alle Sätze von der Eingabedatei gelesen wurden.
  6. Falls mehrere Eingabedateien zur Verarbeitung angegeben wurden, dann wird die nächste Datei geöffnet und der Prozeß wird solange wiederholt bis alle Eingabedateien gelesen wurden.
  7. Nachdem der letzte Satz der letzen Datei gelesen wurde, folgt noch die Ausführung von Instruktionen, die nach der Eingabeverarbeitung auszuführen sind.
    Die END Instruktion der awk-Programmiersprache erlaubt dem Anwender Anweisung zu erteilen, die ausgeführt werden nachdem der letzte Satz gelesen worden ist. Dies ist teilweise nützlich um Kontrollausgaben über die erledigte Arbeit zu machen.

 

Die awk Programmiersprache

Die awk-Programmiersprache besteht aus Anweisungen der Form:

Muster { Aktion }

Falls ein Satz einem angegebenen Muster entspricht, oder ein Feld enthält, das dem Muster entspricht, dann wird die entsprechende Aktion ausgeführt. Ein Muster kann auch ohne eine entsprechende Aktion angegeben werden. In diesem Fall wird die gesamte Eingabezeile ausgegeben.
Eine Aktion ohne ein entsprechendes Muster wird für jede Eingabezeile ausgeführt.

Muster

Es gibt vier Typen von Mustern die in der awk-Programmiersprache verwenden:

Reguläre Ausdrücke

Die erweiterten regulären Ausdrücke, die in awk Verwendung finden, sind recht ähnlich zu denen die beim grep oder egrep Kommando angewendet werden. Die einfachste Form eines Regulären Ausdrucks ist die Angabe einer Reihe von Zeichen die in slashes Schrägstriche eingeschlossen werden. Nehmen wir an, eine Datei mit dem Namen testfile hätte folgenden Inhalt:

Müller, Sepp
Maier, Sepp
Meier, Fritz
Mooshammer, Georg
May, Karl

Wenn wir nun folgendes Kommando eingeben;

awk '/Ma/' testfile

werden alle Zeilen auf die Standardausgabe kopiert, die den String Ma enthalten. In diesem Beispiel enthält das Programm keine Aktionen für das Muster. Die Ausgabe ist:

Maier, Sepp
May, Karl

Für die folgenden Beispiele sind einige Namen von Kursteilnehmern in einer Date abgelegt worden. Die Datei hat den Namen /ELK/tmp/awk_test.txt und hat folgenden Inhalt:

Gander, Reinhold 
Griss, Wolfgang 
Huber, Petra 
Kapfer, Günther 
Böhler, Dieter    
Förg, Thomas 
Nigsch, Markus 
Kaufmann, Diethard 
Schaffer, Roland
Förg, Robert    
Hämmerle, Martin 
Werenka, Roland 
Pommer, Helmut 
Abbrederis, Thomas 
Pichler,    Bernhard 
Nicolussi, Philipp
 

 

Das folgende Beispiel sucht Zeilen welche die Buchstabenfolge hard enthalten.
150:(ENTX) /src/awk >awk '/hard/' $LEO/tmp/akw_test.txt
Kaufmann, Diethard
Pichler, Bernhard
151:(ENTX) /src/awk > 

[x-y]

Hier werden Zeilen gesucht die ein r und dann ein beliebiges Zeichen aus der Menge von a-i enthalten. [a-i] ist wieder eine Aufzählung die für ein Zeichen steht.

151:(ENTX) /src/awk >awk '/r[a-i]/' $LEO/tmp/akw_test.txt
Griss, Wolfgang
Huber, Petra
Förg, Thomas
Kaufmann, Diethard
Förg, Robert
Werenka, Roland
Abbrederis, Thomas
Pichler, Bernhard
152:(ENTX) /src/awk >

[^x-y]

Hier wir ein Set (Menge) negiert. Alle Zeilen, die zwar ein r aber kein a-i sondern alle anderen Zeichen enthalten.

161:(ENTX) /src/awk >awk '/r[^a-i]/' /ELK/tmp/awk_test.txt
Gander, Reinhold
Huber, Petra
Kapfer, Günther
Böhler, Dieter
Nigsch, Markus
Schaffer, Roland
Förg, Robert
Hämmerle, Martin
Pommer, Helmut
Pichler, Bernhard
162:(ENTX) /src/awk >

{n}, {n,m}

Es werden genau zwei m´s gesucht. {n} oder {n,m} gibt die genaue Anzahl von wiederholungen an.

158:(ENTX) /src/awk >awk '/m{2}/' /ELK/tmp/awk_test.txt
Hämmerle, Martin
Pommer, Helmut
159:(ENTX) /src/awk 

~

Hier wird das erste Feld der Zeile genauer untersucht. Alle Zeilen, deren erstes Wort ein (oder mehrere) n enthalten sollen ausgegeben werden.

165:(ENTX) /src/awk >awk '$1 ~ /n/' /ELK/tmp/awk_test.txt
Gander, Reinhold
Kaufmann, Diethard
Werenka, Roland
166:(ENTX) /src/awk >

!~

Zeilen deren erstes Feld kein r enthalten.

167:(ENTX) /src/awk >awk '$1 !~ /r/' /ELK/tmp/awk_test.txt
Nigsch, Markus
Kaufmann, Diethard
Nicolussi, Philipp
168:(ENTX) /src/awk >

^

Zeilen, deren zweites Feld nicht mit R anfängt. ^ steht für den Zeilen oder Wortanfang.

168:(ENTX) /src/awk >awk '$2 !~ /^R/' /ELK/tmp/awk_test.txt
Griss, Wolfgang
Huber, Petra
Kapfer, Günther
Böhler, Dieter
Förg, Thomas
Nigsch, Markus
Kaufmann, Diethard
Hämmerle, Martin
Pommer, Helmut
Abbrederis, Thomas
Pichler, Bernhard
Nicolussi, Philipp
169:(ENTX) /src/awk >


$

Hier werden alle Zeilen, die am Zeilenende ein r haben ausgegeben.

180:(ENTX) /src/awk >awk '$2 ~ /r$/' /ELK/tmp/awk_test.txt
Kapfer, Günther
Böhler, Dieter
181:(ENTX) /src/awk >

 


Relationale Ausdrücke

Die relationalen Operatoren < (kleiner als), > (größer als), <= (kleiner gleich), >= (größer gleich), == (gleich) und != (ungleich) können benutzt werden um Muster zu formen. Zum Beispiel das Muster:

$1 < $4

passt auf alle Sätze, bei denen das erste Feld kleiner als das vierte Feld ist. Die relationalen Operatoren können auch mit Strings arbeiten. Zum Beispiel:

$1 =! "q"

passt auf alle Zeilen deren erstes Feld kein q ist.

$1 <= "d"

passt auf alle Zeilen, deren erstes Feld a, b, c, oder d ist.

Kombinationen von Mustern

Muster können durch diese drei Optionen kombiniert werden:

BEGIN und END Muster

Aktionen die bei einem BEGIN-Muster stehen, werden ausgeführt bevor der erste Eingabesatz gelesen wird.Aktionen die beim END-Muster stehen werden ausgeführt, nachdem die letzte Eingabe gelesen wurde. Mehrere BEGIN- und END-Muster sind erlaubt und werden in der Reihenfolge, in der sie im awk-File stehen ausgeführt. Ein END-Muster kann vor einem BEGIN-Muster in der Datei stehen. Falls eine Datei nur aus einem BEGIN-Muster besteht, werden die Aktionen ausgeführt und keine weiteren Eingaben gelesen. Besteht eine Datei nur aus einem END-Muster, werden alle Eingaben gelesen und erst am Schluß die Aktionen ausgeführt.


Aktionen

Es gibt verschiedene Typen von Aktions-Statements

 

Aktions-Statements werden in sog. braces (geschweifte Klammern) { } eingeschlossen. Falls die Statements ohne ein Muster angegeben werde, können sie auf jede Eingabezeile angewendet werden. Es können mehrere Aktionen angegeben werde, sie müssen lediglich durch einen ; Strichpunkt oder durch Zeilenumbrüche voneinander getrennt werden und sie werden genau in der Reihenfolge ausgeführt wie sie auch in der Datei stehen. Aktionen können folgendes beinhalten:

Arithmetische Befehle

Die mathematischen Operatoren + (Plus), - (Minus), / (Division), ^ (Potenzierung), * (Multiplikation) und % (Modulo) werden in der Form:

Ausdruck Operator Ausdruck

So weist folgendes Statement:

$2 = $1 ^ 3

den Wert des ersten Feldes erhöht um die dritte Potenz dem zweiten Feld zu.

Unäre Statements

Das unäre - (Minus) und das unäre + (Plus) verhalten sich wie in der Programmiersprache C:

+Ausdruck oder -Ausdruck

Increment und Decrement Statements

Das pre-increment und das pre-decrement Statement arbeiten wie in der Programmiersprache C:

++Variable oder --Variable

Das post-increment und das post-decrement Statement arbeiten ebenso wie in der Programmiersprache C:

Variable++ oder Variable--

Zuweisungs Operationen

Die Zuweisungsoperatoren += (Addition), -= (Subtraktion), /= (Division) und *= (Multiplikation) arbeiten wie in der Programmiersprache C, in der Form:

Variable += Ausdruck
Variable -= Ausdruck
Variable /= Ausdruck
Variable *= Ausdruck

Zum Beispiel das Statement:

$1 *= $2

multipliziert die Variable 1 mit der Variablen 2 und weist das Ergenis der Variablen 1 zu. Die Zuweisungsoperatoren ^= (Potenzierung) und %= (Modulo) haben die Form:

Variable1^=Ausdruck1
Variable2%=Ausdruck2

und sind äquivalent zu folgenden Ausrücken der Programmiersprache C:

Variable1=pow(Variable1, Ausdruck1)
Variable2=fmod(Variable2,Ausdruck2)

wobei pow() die Potenzier-Funktion und fmod() die Modulus-Funktion sind.

String-Konkatinierungs Statements

Stringwerte können konkatiniert werden, indem man sie aneinander reiht. Zum Beispiel:

$3 = $1 $2

weist die Verbindung der beiden Strings in den Feldvariablen $1 und $2 der Variablen $3 zu.

Build-In Funktionen

Die awk Befehlssprache benutzt arithmetische Funktionen, Stringfunktionen und allgemeine Funktionen. Die close Subroutine wird zum Beispiel benötigt, um eine geade geschriebene Datei zu schließen, damit sie an anderer Stelle im Programm wieder eingelesen werden kann.

Arithmetische Funktionen

die folgenden arithmetischen Funktionen agieren in der gleichen Art und Weise wie die gleichnamigen Funktionen in der Programmiersprache C:

 

atan2(y,x) Arkustangens von y / x
cos(x) cosinus von x
sin(x) sinus von x
exp(x) Exponentialfunktion von x
log(x) der natürliche Logarithmus von x
sqrt(x) Quadratwurzel von x
int(x) Schneidet x auf einen Integerwert ab
rand() Zufallszahl n mit 0 <= n <= 1
srand([Ausdr]) Setzt den Initialwert für die rand() Funktion auf Ausdr oder nimmt die Uhrzeit falls kein Ausdruck übergeben wird. Der vorherige Wert wird zurückgegeben.

 


String Funktionen

Die Stringfunktionen sind:

gsub(Ere, Repl, [In]) Arbeitet genau gleich wie die sub() Funktion, mit der Ausnahme, daß alle Fundstellen, des Regulären Ausdrucks ersetzt werden
sub(Ere, Repl, [In]) Ersetzt genau die erste Fundstelle des regulären Ausdrucks, der mit dem Parameter Ere angegeben wurde im String, der mit dem In Parameter übergeben wurde mit dem Repl Parameter. Die sub()-Funktion gibt die Anzahl der Ersetzungen zurück. Ein & (Ampersand) kann dazu benutzt werden, den gefundenen regulären Ausdruck im Zielstring wieder zu verwenden. Falls kein In Parameter angegeben wurde, wird als Default der gesamte Eingabesatz ($0) durchsucht.
index(String1, String2) Ermittelt die Position, beginnend bei 1, von String2 im String1. Falls String2 nicht in String1 vorkommt, wird 0 zurückgegeben.
length[(String)] Gibt die Länge von String in Zeichen zurück. Wenn String als Parameter fehlt, dann wird die Länge des gesamten Satzes $0 ermittelt.
blength[(String)] Funktioniert wie length(), gibt aber lediglich die Länge in Bytes zurück.
substr(String,m,(n)) Schneidet einen Substring aus String, beginnend ab Position m bis zum Ende, oder falls n angegeben ist, dann werden n Zeichen ausgegeben
match(String,Ere) Gibt die Position des erweiterten regulären Ausdrucks Ere im String aus oder 0 falls Ere nicht in String enthalten ist. Die Spezialvariable RSTART wird auf den Returnwert gesetzt. Die Variable RLENGTH gibt die Länge des gefundenen regulären Ausdrucks an und wird auf -1 (Minus eins) falls nichts gefunden wurde.
split(String,A,[Ere]) Teilt den String in einzelne Elemente A[1], A[2], ... A[n] des Arrays A auf und gibt den Wert für n zurück. Die Aufteilung wird durch den erweiterten regulären Ausdruck Ere beschrieben. Sollte Ere nicht angegeben worden sein, so wird anhand des Feldtrenners (Spezialvariable FS). Die einzelnen Elemente werden als Stringvariable angelegt, auch wenn einzelne eigentlich numerisch wären.
tolower(String) Wandelt den String in Kleinbuchstaben um. Die Groß-/Kleinkonvertierug wird Anhand der LC_TYPE Kategorie der jeweiligen Locale Einstellungen gehandhabt.
toupper(String) Wandelt den String in Großbuchstaben um. Die Groß-/Kleinkonvertierug wird Anhand der LC_TYPE Kategorie der jeweiligen Locale Einstellungen gehandhabt.
sprintf(Format, Expr, Expr, ...) Formatiert die Ausdrücke Expr anhand der Formatangabe in Format analog zur printf Routine und gibt den resultierenden String zurück.

 

Allgemeine Funktionen

Die allgemeinen Funktionen sind:

close( Expression ) Schließe die Datei oder Pipe, die durch einen print oder printf() Befehl, oder durch einen Aufruf der getline() Funktion mit dem gleichen Expression-Parameter geöffnet wurde. Falls die Datei oder Pipe erfolgreich gerschlossen werden konnte, dann wird 0 zurückgegeben, andernfalls ein negativer, von Null verschiedener Wert. Das close-Statement ist notwendig, wenn im gleichen Programm eine Datei geschrieben und später wieder eingelesen werden soll.
system( Command ) Führt das Kommando, welches mit dem Parameter Command angegeben wurde aus und übergibt den Exit-Status. Es entspricht der system() Systemroutine.
Expression | getline [ Variable ] Liest die Ausgaben in einen Satz, der von einem in Expression angegebenen Kommando während der Ausführung über StdOut ge-piped wurde und stellt das Ergebnis in die angegebene Variable. Jeder weitere Aufruf von getline ließt solange Daten, bis der Stream durch das close() Statemant wieder geschlossen wird.
getline [ Variable ] < Expression Liest einen weiteren Satz aus der in Expression angegebenen Datei in die Variable ein, oder setzt $0 wenn die Variable fehlt.
getline [ Variable ] Liest die nächste Zeile vom aktuellen Eingabefile in die Variable ein. Jeder weitere Aufruf liest eine weitere Zeile von StdIn solange die Datei offen bleibt. Fehlt die Angabe von Variable wird wiederum $0 auf den aktuellen wert gesetzt. Die Varaiblen NF, NR und FNR werden ebenfalls gesetzt.
Hinweis: Alle Formen von der getline() Funktion geben 1 zurück für erfolgreiche Ausführung. Für Dateiende eine 0 und -1 für einen Fehler.

Benutzerdefinierte Funktionen

Benutzerdefinierte Funktionen werden in folgender Form deklariert:

function Name (Parameter, Parameter, ...) { Statements }

Eine Funktion kann von jeder Stelle in einem Programm referenziert werden und ihre Verwendung kann vor der Definition liegen. Damit sind keine Vorwärtsdeklarationen notwendig. Der Gültigkeitsbereich ist global. (Es gibt keine lokalen Funktionen).

Funktionsparameter können entweder scalare (nicht strukturierte) Daten oder Arrays sein. Parameternamen sind lokal nur für diese Funktion gültig; alle anderen Variablennamen sind global.

Funktionsparameter können entweder skalar sein oder es sind Arrays. Parameternamen sind lokal für die Funktion. Alle anderen Variablennamen sind global. Der gleiche Name solte nicht für unterschiedliche Sachverhalte gebraucht werden. Z.B. Ein Funktionsname sollte nicht als Variablenname dupliziert werden, oder als Spezialvariable. Variablennamen mit globalem Gültigkeitsbereich sollen nicht den namen von Funktionen teilen. Skalare und Arrays sollten nicht den gleichen Gültigkeitsbereich haben.

Die Anzahl von Parametern in einer Funktionsdefinition muß nicht mit der Anzahl der Parameter beim Aufruf übereinstimmen. Formale Parameter einer Funktion könnenn also als lokale Variable verwendet werden. Weitere skalare Parameter werden mit einem leeren String oder dem Wert Null initialisiert; zusätzliche Arrayparameter werden mit einem leeren Array initialisiert.

Beim Funktionsaufruf darf kein sog. White-Space zwischen dem Funktionsnamen und der öffnenden Klammer stehen. Funktionsaufrufe dürfen verschachtelt werden und dürfern Rekursiv sein. Nach jeder Rückkehr aus einem verschachtelten oder rekursiven Funktionsaufruf sind die Aufrufparamter unverändert. Lediglich Array-Parameter werden by reference übergeben und somit kann der Inhalt verändert werden. Der return Befehl wird verwendet um einen Returnwert zu setzen.

Innerhalb einer Funktionsdefinition sind Zeilenumbrüche optional vor der öffnenden Klammer { und nach der schließenden Klammer }.

function average ( g,n)
{ 
  for ( i in g)
    sum=sum+g[i]
  avg=sum/n
  return avg          
} 

An die Funktion average wird ein Array, g, und eine Variable, n, mit der Anzahl Elemente des Array übergeben. Dier Funktion ermittelt dann den Durchschnitt und gibt ihn zurück.


Bedingungen

Die meisten Bedingungsstatements der awk-Sprache haben ihre Entsprechung in der Programmiersprache C. Alle Bedingungen erlauben die Anwendung von { } um mehrere Statements zu einem Block zusammen zu fassen. Eine zusätzliche Leerzeile kann zwischen der Bedingung und dem Anweisungsteil platziert werden. Zeilenumbrüche oder ; werden dazu benutzt mehrere Befehle in einem Block voneinander zu trennen. Die sechs Bedingungsstatements in der Programmiersprache C sind:

if erfordert die folgende Syntax:

if (Ausdruck) { Anweisung } [ else Aktion ]

while erforder die folgende Syntax:

while ( Ausdruck ) { Anweisung }

for erfordert die folgende Syntax:

for (Ausdruck ; Ausdruck ; Ausdruck)
{ Anweisung }

break verläßt eine for- oder eine while-Schleife

continue zwingt die Schleife in die nächste Iteration


Es gibt fünf weitere Sprachkonstrukte in awk, die nicht an die Sprache C angelehnt sind:

for ... in hat folgende Syntax:

for (Variable in Array) { Anweisung }

Das for ... in Statement setzt den Wert der Variablen auf jeden Index-Wert der Array-Variable. Einen Index-Wert nach dem anderen und in keiner bestimmten Reihenfolge, dann wird die Anweisung für jeden Schleifendurchlauf ausgeführt. Eine Anwendung des for ... in Befehls wird weiter unten beim delete-Befehl beschrieben.

if ... in hat folgende Syntax:

if ( Variable in Array ) { Anweisung }

Das if ... in Statement prüft die existenz eines Array-Elementes. Die Anweisung wird ausgeführt wenn das Array-Element gefunden wurde.


delete erfordert folgende Syntax:

delete Array [ Ausdruck ]

Die delete Anweisung löscht beides, das Array-Element das mit dem Array-Parameter angegeben wird, wie auch den Index der durch den Ausdruck angegeben wird. Zum Beispiel, die Anweisung:

for (i in g)
   delete g[i]; 

löscht jedes Element des Arrays g[].


exit erfordert die folgende Syntax:

exit [ Ausdruck ]

Die exit-Anweisung ruft als erstes alle END-ktionen in der Reihenfolge ihres Auftretens und beendet dann das awk-Kommando mit einem Status, der durch den angegebenen Ausdruck beschrieben wird. Es werden keine weiteren END-Aktionen mehr gerufen, wenn exit innerhalb einer END-Aktion vorommt.


# erfordert die folgende Syntax:

# Kommentar

Die # Anweisung plaziert Kommentare. Kommentare enden immer mit einem Zeilenumbruck, können aber irgend wo in der Zeile beginnen.


next stoppt die Verarbeitung des aktuellen Eingabesatzes und setzt die Verarbeitung mit dem nächsten Eingabesatz fort.


Ausgabe Befehle

Es gibt zwei verschiedene Formen des Ausgabebefehls

print erfordert die folgende Syntax:

print [ Liste von Ausdrücken ] [ Umleitung ] [ Ausdruck ]

Die print Anweisung schreibt den Wert eines jeden Ausdrucks aus der Liste auf die Standard-Ausgabe. Jeder Ausdruck wird durch den aktuellen Wert, der OFS Spezialvariable separiert. Jeder Satz wird durch den aktuellen Wert der ORS Spezialvariable beendet.

Die Ausgabe kann durch Verwendung des Umleitungsparameters, der die drei Werte für Ausgabeumleitungen, dem > (größer als), dem >> (doppelten größer als) und dem | (Pipe) annehmen kann. > und >> leiten auf eine Datei, die im Ausdruck angegeben wird oder an ein Kommando ( falls mit dem | gearbeitet wurde).

print $1 $2 >> "$GWORA/daten/dfue/dfue/blah.txt"
print $1 $2 | rm

printf erfordert die folgende Syntax:

printf Format [ , Liste von Ausdrücken ] [ Umleitung ] [ Ausdruck ]

Die printf Anweisung schreibt die Ausdrücke der Liste auf die Standard-Ausgabe und formatiert nach dem Format-Parameter. Die Printf-Funktion arbeitet exakt so wie das printf Kommando von Unix und durch die Zugabe von Klammern ähnelt der Befehl sehr der Programmiersprache C. Die Umleitung funktioniert identisch zur print Anweisung.

Achtung: Wenn der Ausdruck, auf den umgeleitet wird einen Pfad und Dateinamen angibt, muß dieser in doppelte Anführungszeichen gestellt werden


Variable

Variable können skalar sein, sie können Feldvariable, Array oder Spezial-Variable sein. Variablennamen können nicht mit einem Punkt beginnen. Sie werden verwendet, indem man sie einfach referenziert (beim Namen nennt). Mit einer Ausnahme, den Funktionsparametern. Diese müssen nicht explizit deklariert werden. Nicht initialisierte skalare Variable und Array-Elemente haben sowohl einen numerischen Wert 0 (Null) als auch einen leeren String "" als Wert.

Die Variablen nehmen aus dem Kontext heraus einen numerischen oder String-Wert an. Zum Beispiel:

x = "4" + "8"

weist der Variablen x den Wert 12 zu! Strinkonstanten müssen in " " (doppelte Abführungszeichen) eingeschlossen werden.

Es gibt keine expliziten Konvertierungen zwischen Zahlen und Strings. Um einen Ausdruck zwingend numerisch werden zu lassen muß man einfach den Wert 0 dazu addieren. Ebenso ist es durch anhängen eines leeren Strings möglich einer Variablen einen String-Typ zuzuweisen.

Feldvariable

Feldvariablen erkennt man am vorangestellten $ (Dollar) Zeichen gefolgt von einer Zahl oder eines numerischen Ausdrucks. Dem ersten Feld wird die Variable $1 zugewiesen, dem zwiten Feld die Variable $2 und so weiter. Die Variable $0 enthält den gesamten Eingabesatz. Neue Feldvariablen kann man durch Zuweisung eines Wertes kreieren. Wenn man nun einem nicht existierenden Feld einen Wert zuweist, dann werden zum einen dazwischen liegende Feldvariablen angelegt und mit NULL belegt, zum anderen wird der Wert der Variablen $0 neu berechnet. Die neuen Felder werden durch den aktuellen Feldseperator getrennt ( der Wert steht in der FS Spezialvariable). Leerzeichen und Tabulatoren sind die default Feldtrenner. Um den Feldtrenner zu ändern kann man die Option -F beim awk Aufruf verwenden oder der FS Spezialvariablen innerhalb des Programms einen neuen Wert zuweisen.

Arrays

Arrays sind anfangs leer und ihre Größen ändern sich dynamisch. Arrays werden durch eine Variable repräsentiert und in [ ] (eckigen Klammern) subscribiert. Subscripts oder Element-Identifikatoren auch Strings sein. Auf diese Weise können sog. assoziative Arrays dargestellt werden. Zum Beispiel das Programm:

/rot/ { x["rot"]++ }
/grün/ { y["grün"]++ }

erhöht sowohl den rot-Zähler, als auch den grün-Zähler.

Arrays können mit mehr als einem Index indiziert werden, ähnlich wie mehrdimensionale Arrays anderer Programmiersprachen. Da Arrays in awk wirklich nur eindimensional sind, werden die durch Komma getrennten Indizes zu einem simplen String zusammengefügt, wobei jeder Ausdruck durch den Inhalt der Spezialvariablen SUBSEP getrennt wird. Deswegen sind die beiden folgenden Ausdrücke äquivalent:

x[expr1, expr2, ...exprn]

und

x[expr1SUBSEPexpr2SUBSEP...SUBSEPexprn]

Wenn der in Operator verwendet wird, sollten multidimensionale Indizes am besten in Klammern dargestellt werden. Mit Ausnahme des in Operators fürt jede Referenzierung eines nicht existierenden Array-Elements sofort zu dessen Anlage.

Spezielle Variable

Die im Folgenden beschriebenen Variablen haben eine besondere Bedeutung

ARGC

Die Anzahl von Elementen im ARGV-Array. Der Wert kann geändert werden.

ARGV

Das Array enthält alle Filevariablen und Variablenzuweisungen die in der Kommandozeile übergeben wurden. Es wird bei 0 angefangen zu nummerieren und das letzte Element steht an der Stelle ARGC - 1. Das jeweils nächste Element stellt die nächste Eingabedatei dar, bis

CONVFMT

Das printf-Format um Zahlen in Strings zu konvertieren (Mit Ausnahme der Ausgabebefehler, hier wird der Wert der OFMT-Variablen verwendet). Der Default ist "%.6g"

ENVIRON

Dieses Array repräsentiert die aktuelle Umgebung in der das awk-Kommando ausgeführt wird. Jedes Element im Array ist von der Form:

ENVIRON ["Environment Variablenname"] = EnvironmentVariablenWert

Die Werte werden gesetzt, wenn das awk-Kommando gestartet wird. Das Environment wird in der Form benutzt bis awk beendet wird, unabhängig davon ob die Variable geändert wird.

FILENAME

Der komplette Dateiname incl. Pfad, der aktuell in bearbeitung befindlichen Datei. Während der Ausführung der BEGIN Aktion ist der Wert von FILENAME undefiniert und bei der Ausführung der END Aktion enthält FILENAME den Namen der letzten Eingabedatei die bearbeitet wurde.

FNR

Die Nummer das aktuellen Eingabesatzes der momentan in Bearbeitung befindlichen Datei.

FS

Der Eingabefeld-Trenner. Der Defaultwert ist " " (Leerzeichen). In diesem Fall wird jedes sogenannte Whitespace als Trennzeichen verwendet. Die Variable FS kann auf zweierlei Weise verwendet werden:

NF

Gibt die Anzahl der Felder in einem Eingabesatz an. Das Limit ist 99. Innerhalb einer BEGIN Aktion ist der Wert von NF undefiniert, es sei denn es wird eine getline()-Funktion ohne einen Parameter ausgeführt. Innerhalb einer END Aktion hat NF immer noch den Wert, der durch die Verarbeitung der letzten Zeile entstanden ist, es sei denn es wurde wiederum die getline()-Funktion ohnen einen Parameter gerufen.

NR

Die Nummer des aktuellen Eingabesatzes. Innerhalb der BEGIN Aktion ist der Wert 0. Innerhalb der END Aktion ist der Wert gleich der Nummer des letzten Satzes, der verarbeitet wurde.

OFMT

Das printf Format um Zahlen in Ausgabebefehlen in Strings zu konvertieren.
Der Defaultwert ist "% .6g"

OFS

Der Ausgabefeld Sepeartor (Default ist ein Leerzeichen)

ORS

Der Ausgabe Satztrenner (Default ist ein "\n" new-line Zeichen)

RLENGTH

Die Länge des Strings, der in der match()-Funktion passte.

RS

Trennzeichen für Eingabezeilen (Default ist ein "\n" new-line Zeichen). Falls der Wert von RS nicht gesetzt ist, wird eine Folge von einer oder mehreren Leerzeilen als Satztrenner verwendet. Wobei führende oder nachfolgende Leerzeichen in einer Zeile nicht in leere Sätze konvertiert werden. Das new-line Zeichen wird dann immer als Feld-Trenner benutzt, unabhängig vom Wert der Variablen FS.

RSTART

Die Startposition des durch die match()-Funktion gefundenen Strings, nummeriert von 1 aufsteigend. Der Wert ist identisch mit dem Rückgabewert der match()-Funktion.

SUBSEP

Trennt mehrere Subscripts. Der Defaultwert ist \031.

Flags

-f ProgramFile

enthält Anweisungen für das awk-Kommando. Die unter ProgramFile angegebene Datei wird geöffnet und die darin enthaltenen awk-Anweisungen werden ausgeführt. Wird die Option -f mehrfach angeführt, werden die einzelnen Dateien in der Reihenfolge ihrer Aufzählung aneinandergereiht ausgeführt.

-F Ere

Der angegebene erweiterte reguläre Ausdruck wird als Feldtrennzeichen verwendet. Default ist ein Leerzeichen.

-v Zuweisung

Weist einer Variablen einen Wert zu. Die Variable ist dann innerhalb des awk-Programms bekannt. Der Namensteil wird als Variablenname verwendet und kann aus verschiedenen Buchstaben, Underscores oder Zahlen bestehen. Er muss jedoch immer mit einem Underscore oder einem Buchstaben beginnen. Der Wert wird behandelt, als stünde er wie ein String in Anführungszeichen. Falls es ein numerischer Wert ist, wird automatisch eine numerische Variable erzeugt.

Die Zuweisungen werden ausgeführt bevor irgend eine Aktion und auch bevor die BEGIN-Aktion ausgeführt wird.

Zuweisung

Diese Zuweisung wirkt genauso wie die Zuweisung mit der Option -v, sie wird lediglich erst nach der Ausführung einer BEGIN-Aktion angewendet. Diese Zuwesungen müssen aber vor den Dateinamen in der Kommandozeile erfolgen.

Dateiname

Gibt den Namen der Eingabedatei an, die untersucht werden soll. Wenn kein Dateiname angegeben wuden, jedoch ein - (Minus) in der Kommandozeile steht, wird die Eingabe von StdIn gelesen. So kann awk auch als Filter verwendet werden. Dies ist z.B. in Scripts nützlich, in denen die zu bearbeitenden Daten direkt hinter (unter) dem awk-Kommando stehen.

'Programm'

Es können auch direkt awk-Anweisungen über die Kommandozeile angegeben werden. Hier ist es jedoch nötig umschliessende einfache Anführungszeichen zu verwenden.


Die Aufrufsyntax lautet:

awk [ -F Ere ] [ -v Zuweisung ] ... { -f ProgramFile | 'Programm' } [[ Dateiname | Zuweisung ]] ...

Exit Status:

0 Die Ausführung war erfolgreich
>0 Es ist ein Fehler aufgetreten

 


Beispielsammlung

Was wird gemacht unter UNIX unter Windows
Summieren von Dateigrössen
ls -al |
awk '{a=a+$4}
END{print a}'
dir |
gawk "{a=a+$3}
END{print a}"
Anzahl Felder oder Spalten ausgeben
ls -al |
awk '{print $NF}'
dir |
gawk "{print $NF}"
Die ersten dreizehn Spalten unterdrücken
awk '{
for (i=1;i<=13;i++) {
   $i=""
} print}' st05.txt
gawk "{
for (i=1;i<=13;i++) {
   $i=\"\"
} print}" st05.txt
Nur einige Zeilen in der Datei zählen und anzeigen
ls -al | 
awk '/d/{a=1}
{if (a==1){n++; print}}
/o/{a=0}
END{print (n" lines !")}'
dir | 
gawk "/d/{a=1}
{if (a==1){n++; print}}
/o/{a=0}
END{print (n\" lines !\")}"
Die dritte Spalte einer CSV-Datei anzeigen
awk 'BEGIN{FS=","}
{print $3}' file.csv
gawk "BEGIN{FS=\",\"}
{print $3}" file.csv
Nur Zeilen anzeigen, die sechs Spalten enthalten
df -k |
awk 'NF==6{print}'
dir |
gawk "NF==4{print}"
Nur Zeilen eines bestimmten Musters anzeigen
awk '/^#include/{print}' stdio.h
gawk "/^\[/{print}" system.ini
Gleitkommaoperationen ausführen
awk 'BEGIN{print 1/5.3}'
gawk "BEGIN{print 1/5.3}"


Einfache AWKs

Im Folgenden sind einige einfache AWKs als Beispiele angeführt. Mir ist bewusst, daß es immer eine bessere Lösung für ein Problem gibt. Aber oft fehlen einem die Mittel oder einfach die Zeit in ein Handbuch zu schauen. Deshalb bin ich an Alternativen immer interessiert. Jeder ist aufgerufen, schöne und nützliche AWKs an mich zur Veröffentlichung zu senden.

 

Wenn man folgendem awk die Ausgabe eines describe-Befehls von Oracle als Eingabe gibt kann man sich lange Select-Listen recht einfach generieren. Das spart enorm Tipparbeit.

     1
     2  # Skript um lange selects zu generieren
     3  # Michael Braun,
     4
     5  BEGIN   {
     6    print "      *--------------------------------------------------"
     7  }
     8  # Die Statistik-Information wird nicht bearbeitet
     9  /AEND_TS_DT/ { getline }
    10  /AENDERER/   { getline }
    11  /ANLAGE_DT/  { getline }
    12  /ANLEGER/    { getline }
    13
    14  /^ [A-Z]*/ {
    15    if ($1 == "Name")
    16      {;}
    17    else if (substr($1,1,2) == "--") {;}
    18    else
    19      {
    20        if (NR > 4) printf ",\n";
    21        printf("                   %s",$1);
    22      };
    23  }
    24
    25
    26  END {
    27    printf "\n";
    28    print "      *--------------------------------------------------"
    29  }

Weitere Informationen

Die Homepage von Brian W. Kernighan enthält viele interessante Informationen und Links. Hier ist auch der Link zur AWK-Hompage. Ebenso interessant ist die Homepage von diesem alten Bekannten, Dennis M. Ritchie, ist etwas für true-believers.