[ awk-Tutorium ]

 

Kapitel 2

Bedingungen und Variablen

 

2.1    Bedingungen

Wir haben bereits die Bedingung /[text]/ kennengelernt, die nach dem Text [text] sucht. Dabei kann [text] auch einfache so genannte reguläre Ausdrücke enthalten:

.
bedeutet ein beliebiges Zeichen: /Ha.s/ findet »Hans«, »Haus«, »Hass«, »Hals«.

^
am Anfang des Ausdrucks bedeutet, dass der gesuchte Text am Anfang der Zeile stehen muss. Leerzeichen am Anfang werden berücksichtigt. /^a/ findet »alles«, aber nicht » alles«.

$
am Ende des Ausdrucks bedeutet, dass der Text am Ende stehen muss. /z$/ findet »ganz«, nicht »ganzes«.

[ab]
bedeutet, dass einer der Buchstaben »a« oder »b« an dieser Stelle stehen muss. /Ha[ul]s/ findet »Hals« und »Haus«, nicht aber »Hans«.

[a-z]
bedeutet, dass hier ein Buchstabe von »a« bis »z« stehen muss. Das - bezieht sich auf die Nummer des Zeichens im ASCII-Code. /Ha[i-n]s/ findet »Hals«, »Hans«, aber nicht »Hass« oder »Haus«.

   Will man eines dieser speziellen Zeichen im Klartext finden, so muss ein Backslash, der rückläufige Schrägstrich, vorangestellt werden: \. findet einen Punkt, \\ einen Backslash. Der Backslash kann auch bei anderen Zeichen benutzt werden, er findet dann dieses Zeichen. Wer also nicht genau weiß, ob ein Zeichen eine besondere Bedeutung hat, stellt einfach einen Backslash voran: \Y findet ein großes Ypsilon.

Es gibt weitere Bedingungen, die meist in einer der Programmiersprache C ähnlichen Syntax angegeben werden:

    a == b  ist wahr, wenn a und b gleich sind.
    a != b  ist wahr, wenn a und b ungleich sind.
    a < b   ist wahr, wenn a kleiner als b ist.
    a <= b  ist wahr, wenn a kleiner als oder gleich b ist.
    a > b   ist wahr, wenn a größer als b ist.
    a >= b  ist wahr, wenn a größer als oder gleich b ist.

Das Skript

    $1=="NODE" { print $2 }

schreibt also das zweite Wort heraus, wenn das erste »NODE« ist. Zeichenketten, so genannte Strings, müssen hier immer in Anführungszeichen stehen, um deutlich zu machen, dass es sich um einen String und nicht um eine Variable handelt.

   Vorsicht bei der Prüfung auf Gleichheit: a = b belegt a mit dem Wert von b. In awk muss die Prüfung auf Gleichheit wie in C mit einem doppelten Gleichheitszeichen erfolgen!

(Es ist sogar noch schlimmer: a = b ist für awk wahr, wenn b nicht Null ist. Die Belegung von a erfolgt aber trotzdem: Etwas wie wie

    $1="xxx" { print $1, $2, $3 }

hat merkwürdige Folgen.)

Für Strings gibt es zwei weitere Operatoren: ~ und !~, die prüfen, ob ein String einen regulären Ausdruck enthält oder nicht. /^[0-9]/ und $0 ~ /^[0-9]/ bewirken dasselbe: Sie überprüfen, ob die Zeile mit einer Ziffer beginnt. Mit ~ kann man also beliebige Strings auf reguläre Ausdrücke hin überprüfen.

Bedingungen können mit so genannten logischen Operatoren miteinander verknüpft werden:

a && b
ist wahr, wenn beide Bedingungen a und b wahr sind.

a || b
ist wahr, wenn mindestens eine der Bedingungen a und b wahr ist.

!a
ist wahr, wenn a falsch ist (Negation).

Bedingungen können weiterhin in Klammern geschachtelt werden, um Prioritäten bei der Auswertung zu setzen. Außerdem gibt es noch zwei nützliche Regeln aus der Logik, die Gesetze von de Morgan:

    !(a && b) == !a || !b
    !(a || b) == !a && !b

Außerdem können zwei Bedingungen hintereinander, durch ein Komma getrennt, angegeben werden. Dann werden die Anweisungen für alle Zeilen ausgeführt, die zwischen einer Zeile, für die die erste Bedingung gilt, und der nächsten, für die die zweite gilt, liegen.

    /Anfang/, /Ende/

Schreibt alle Zeilen, die zwischen den Wörtern »Anfang« und »Ende« liegen. Die erste Bedingung ist also eine Start-, die zweite eine Abbruchbedingung.

Es gibt noch zwei weitere Bedingungen in awk, die sehr wichtig sind, die wir aber erst später benutzen werden:

BEGIN
Die Anweisungen, die nach BEGIN stehen, werden ganz am Anfang ausgeführt, bevor die erste Zeile eingelesen wird.

END
Analog dazu werden die Anweisungen nach END nach dem Einlesen aller Zeilen abgearbeitet.

 

2.2    Variablen

Das Konzept der Variablen in awk ist sehr mächtig. Variablen müssen nicht, wie in Programmiersprachen allgemein üblich, deklariert werden, bevor sie benutzt werden. Um eine Variable zu benutzen, setzt man sie einfach im Skript ein. Jede Varaible hat zu Beginn des Skripts den Wert 0.

Dazu ein Beispiel:

    awk '/NODE/ { n = n+1 }; END { print n }' xxx.dat

Dieses Skript zählt die Zeilen, in denen »NODE« vorkommt, in der Variable n und gibt n am Ende aus. Dies ist äquivalent zu

    grep -c NODE xxx.dat

Verschiedene Anweisungen können durch Semikola oder Zeilenumbrüche voneiander getrennt hintereiander angegeben werden. Letzteres funktioniert natürlich nur, wenn das Skript in einer separaten Datei steht. Wenn eine Anweisung über mehrere Zeilen geht, so müssen alle Zeilen der Anweisung außer der letzten mit einem Backslash enden.

   Anstelle der Anweisung n = n + 1, die wörtlich bedeutet: »Weise der Variable n den jetzigen Wert von n plus eins zu, und die nichts anderes macht, als n um eins zu erhöhen, kann man in awk abkürzend schreiben n++.

Variablen in awk können zwei Grundtypen besitzen: Zahl oder String. Dabei ist awk bei der Interpretation, um welchen Typ es sich handelt, flexibel.

Mit Zahlen können folgende Operationen durchgeführt werden:

    +           Addition
    -           Subtraktion
    *           Multiplikation
    /           Division
    %           Modulo-Division
    ^           Potenzieren

Das Ergebnis der Division ist eine Fließkommazahl. Mit Modulo-Division bezeichnet man den Rest einer Ganzzahldivision: 7%3 ist 1, da sieben geteilt durch drei einen Rest von eins lässt.

   Für alle diese Funktionen gibt es Abkürzungen, wenn dieselbe Variable auf beiden Seiten vorkommt. So kann man x = x + 10 als x += 10 schreiben. Analog dazu gibt es die Operatoren -=, *=, /=, %= und ^=. Diese Schreibweise ist für Anfänger aber oft verwirrend, deshalb ist es vermutlich besser, den Ausdruck komplett anzugeben.

   Die Operatoren ++ und -- können vor oder hinter Variablen stehen. ++ vor einer Variable (Präfix) bedeutet »erhöhe die Variable um eins, und werte dann aus«, nach einer Variable (Postfix) bedeute es »werte die Variable aus, erhöhe sie dann um eins«.

Ist x 5, so erhöht sich der Wert bei print ++x und bei print x++ in beiden Fällen auf 6. Im ersten Fall wird jedoch »6«, im zweiten »5« ausgegeben.

Die einzige elementare Funktion für Strings ist das Anhängen eines anderen Strings, das einfach durch Hintereinaderschreiben der Strings, durch mindestens ein Blank getrennt, geschieht:

    name = "Hans" "Meiser";
    print name;

gibt »HansMeiser« aus. Es wird also kein Leer- oder anderes Zeichen zwischen die verketteten Strings geschrieben.

Wie bereits erwähnt, können Variablen ihren Typ ändern. Führt man mit Strings eine mathematische Operation durch, so ist das Ergebnis eine Zahl. Andersherum geht es aber auch: Fügt man an eine Zahl einen String an, so ist das Ergebnis ein String.

Dazu ein Beispiel:

    $1=="NODE" {x = x + $2; n = n + 1}
    END {print x, n, x/n}

Hier werden für alle Zeilen, in denen das erste Wort »NODE« ist, die Zahlenwerte der zweiten »Wörter« aufaddiert. Am Ende wird die Summe, die Anzahl und der Durchschnitt ausgegeben.

Es gibt keine explizite Anweisung, um Strings in Zahlen umzuwandeln und umgekehrt. Um sicherzugehen, kann man folgendes machen: x + 0 ist eine Zahl, x "" ist ein String. ("" ist der Nullstring, ein String ohne Inhalt.)

   Der numerische Wert von Strings, die keine Zahl enthalten, ist Null: "Anna" hat einen numerischen Wert von Null. awk kann aber die Exponentialschreibweise für Fließkommazahlen erkennen: "2.4E-3" wird korrekt als 0,0024 interpretiert.

Aufgaben:

Aufgabe 2a
Schreibe ein Skript, das nur jede zweite Zeile eines Datensatzes ausgibt.

Aufgabe 2b
Wie sähe ein Skript aus, das den Shell-Befehl wc (word count) simuliert? wc gibt die Anzahl der Zeilen, Wörter und Zeichen in einer Textdatei aus.

Aufgabe 2c
Wie sieht ein Skript aus, das das Produkt der zweiten und dritten Zahl einer Zeile bildet, wenn das erste Wort »mult« ist, und diese dann aufsummiert. Die Ausgabe soll nur die Summe der Produkte sein, nicht die Produkte selbst.

Aufgabe 2d
Wie sieht ein Skript aus, das vor jeder Zeile, die eingerückt ist, also mit einem Leerzeichen oder einem Tab beginnt, eine Leerzeile schreibt? (Ein Tab wird in awk durch die Zeichenfolge \t repräsentiert.)

Aufgabe 2e
Schreibe ein Skript, das eine Zeile nur dann ausgibt, wenn das erste Wort von dem in der vorhergehenden Zeile verschieden ist.


Nächstes Kapitel
Voriges Kapitel
nach oben
Inhalt


________
Startseite --> Dies & das --> awk-Tutorium --> Kapitel 2
Übersicht
Martin Oehm

[ www.martin-oehm.de - Startseite ]
[ Dies & das ]
[ awk-Tutorium ]

Inhalt

Vorwort

1. Kapitel
2. Kapitel
3. Kapitel
4. Kapitel
5. Kapitel

Kurzübersicht
Lösungen