Kapitel 4 Komplexere Programme4.1 Wenn-dann KonstrukteBedingungen können nicht nur außerhalb des Anweisungsblocks mit geschweiften Klammern stehen, sie können auch innerhalb abgefragt werden. Dazu gibt es die if-Anweisung: if ([Bedingung]) [einzelne Anweisung] Wenn mehrere Anweisungen von der Bedingung abhängig ausgeführt werden sollen, so müssen sie zu einem Block in geschweiften Klammern zusammengefasst werden. Also sind die beiden Zeilen $1=="x" { print } { if ($1=="x") print } gleichwertig. Für einfache Abfragen sind Abfragen außerhalb des {}-Blocks wohl übersichtlicher, if-Anweisungen dienen eher zur weiteren Abfrage innerhalb des Blocks. Einen großen Vorteil bietet die if-Anweisung jedoch: Mit dem Zusatz else können Ausführungen angegeben werden, die nur dann ausgeführt werden, wenn die Bedingung nicht erfüllt ist: if ([Bedingung]) [Anweisung A] else [Anweisung B] Auch hier können Anweisungen zu Blöcken zusammengefasst werden. Wird nur eine einzelne Anweisung zu [A] angegeben, so muß diese mit einem Semikolon abgeschlossen werden, auch wenn dies auf den ersten Blick den »Satzfluss« stört. Also, wieder ein Beispiel: { if (/^\$/) print > "comment.dat"; else print; } Hier werden alle Zeilen, die mit einem »$« beginnen, in eine separate Datei comment.dat geschrieben, alle anderen auf den normalen Output. Mit > können wie in der Shell Ausgaben in Dateien umgeleitet werden. Achtung: Dateinamen sind in awk immer Strings und müssen daher in Anführungsstrichen stehen. 4.2 SchleifenEin weiteres wichtiges Instrument sind Schleifen. Eine typische Schleife ist die while-Schleife: while ([Bedingung]) [Anweisung] Hier wird die Anweisung solange ausgeführt, bis die Bedingung falsch wird. ist die Bedingung von Anfang an falsch, passiert nichts: n = 1; while (n < 256) {print n; n*=2} Natürlich muss in der Anweisung etwas passieren, das die Bedingung irgendwann einmal falsch werden lässt. Etwas wie n = 0; while (n < 5) {print n} führt zu einer so genannten Endlosschleife, die ununterbrochen den Wert 0 ausgibt, der natürlich immer kleiner als fünf ist. Eine Abwandlung der while-Schleife ist die do-while-Schleife: do [Anweisung] while ([Bedingung]) Auch hier werden die Anweisungen solange durchlaufen, bis die Bedingung falsch wird. Allerdings wird die Anweisung immer mindestens einmal ausgeführt, was bei der reinen while-Schleife nicht sein muss. Schleifen werden oft zum Zählen verwendet. Hierfür gibt es eine besondere Schleife, for: for ([Init]; [Bedingung]; [Update]) [Anweisung] Dies ist eine Abkürzung für [Init]; Eine Schleife, die die Variable i von 0 bis 99 zählt, und sie ausgibt, wäre for (i=0; i<100; i++) print i; Jeder der drei Ausdrücke in der Klammer kann weggelassen werden. Fehlt z.B. [Init], so wird der momentane Wert der Variable benutzt. Mit break kann aus jeder Schleife - auch aus einer Endlosschleife - herausgesprungen werden in die nächsthöhere. Mit continue wird der Durchlauf übersprungen, es geht bei [Update] weiter. 4.3 Funktionenawk erlaubt die Definition eigener Funktionen, in anderen Sprachen auch Subroutinen oder Prozeduren genannt. Eine Funktion wird folgendermaßen definiert: function [Name] ([Argumente])
{ Die Definition der Funktion muss außerhalb aller Blöcke in geschweiften Klammern stehen. Als Argumente können beliebig viele Variablen, durch Kommas getrennt, angegeben werden. Wenn es keine Argumente gibt, muss trotzdem ein leeres Klammerpaar angegeben werden: function multiply(i,j) { print i "*" j, "=", i*j; } Der Aufruf der Funktion aus einem Anweisungsblock heraus wäre multiply($4,$5); zum Beispiel. Alle Variablen, die als Argumente übergeben werden, sind lokal. Das heißt, sie sind nur innerhalb des Anweisungsblocks der Funktion bekannt, nicht jedoch außerhalb. Es können jedoch globale Variablen, die außerhalb der Funktion definiert wurden, benutzt werden. Wenn eine Variable innerhalb einer Funktion zum ersten Mal benutzt, also implizit initialisiert wird, ist sie eine globale Variable. Die Ausnahme ist hier, wenn es eine lokale Variable gibt, die denselben Namen wie eine globale Variable hat. In diesem Fall ist die lokale gemeint. Alle Variablen, die außerhalb von Funktionen definiert werden, sind global. Achtung! Die erste Klammer muss direkt an den Funktionsnamen anschließen, sonst hat awk Schwierigkeiten bei der Interpretation des Aufrufs! Eine nützliche Sache ist die Rückgabe von Werten aus einer Funktion. Dies geschieht mit return: function max(i,j) { if (i > j) return i; else return j; } Diese Funktion schreibt nichts auf den Bildschirm, sondern gibt nur einen Wert zurück. Der Aufruf max(1,3) bringt nichts, obwohl die Anweisungen der Funktion abgearbeitet werden. Um den Rückgabewert der Funktion nutzen zu können, muß der Aufruf lauten: j = max(1,3) Dann hat j den Wert des Maximums von 1 und 3, also 3. Man kann den Wert aber auch direkt in einem Aufruf verwenden: print max(1,3) schreibt eine 3. Man kann sogar soweit gehen, den Rückgabewert als Argument in einem weiteren Funktionsaufruf zu benutzen: print max(max(1,3),8) schreibt eine »8«. Man kann die Funktion auch aus sich selbst heraus aufrufen, dies nennt man Rekursion: function factorial(n) { if (n==1) return 1; else return n*factorial(n-1); } ist eine rekursive Funktion zum Berechnen von Fakultäten. Aber Vorsicht: Da die lokalen Variablen für jeden Aufruf extra angelegt werden müssen, kann es bei langen Rekursionen zum Überlauf des Stapelspeichers kommen. 4.4 Weitere FunktionenNeben den bereits bekannten Stringoperationen gibt es folgende Funktionen:
4.5 FelderFelder sind Werte, die unter einem Namen zusammengefasst sind und mit einem Index versehen werden. Üblicherweise haben Felder ganzzahlige, aufeianderfolgende Indizes. Daten in einem Feld werden mit dem gemeinsamen Feldnamen und ihrem Index in eckigen Klammern angesprochen: [Feld] [[Index]] Ein Feldeintrag ist wie eine Variable: Er kann mit anderen Werten verglichen werden und einen Wert zugewiesen bekommen. Felddaten sind zu Anfang Null oder der Nullstring. (Genau wie Variablen können Felddaten Zahlen oder Strings sein.) Das besondere an Feldindizes in awk ist, dass sie nicht unbedingt aufeinanderfolgen und nicht numerisch sein müssen. Das macht das Arbeiten mit Feldern in awk besonders flexibel: /^NODE/ { nodeID = substr ($0,9,8) + 0; x[nodeID] = substr($0,17,8) + 0; y[nodeID] = substr($0,25,8) + 0; z[nodeID] = substr($0,33,8) + 0; } Für Felder gibt es eine besondere Bedingung, ([Index] in [Feld]) prüft, ob es in [Feld] einen Eintrag unter [Index] gibt. Diese Notation kann auch für for-Schleifen verwendet werden: for ([Index] in [Feld]) [Anweisung] arbeitet die Anweisung für alle Indizes im Feld ab. Das ist oft sehr praktisch: /^[A-Za-z]/ { a[$1]++ } END { for (i in a) print a[i], "Mal", i; } zählt zu Beispiel die Anzahl und Typen der verwendeten Keywords, wenn man davon ausgeht, dass Keywords mit Buchstaben anfangen. Feldeinträge können mit delete [Feld] [[Index]] wieder aus dem Feld gelöscht werden. In einem Feld können auch mehrere Indizes verwendet werden, die dann durch Kommas getrennt innerhalb der eckigen Klammern stehen: [Feld] [[Index1], [Index2], [Index3]] Aufgaben: Aufgabe 4a Aufgabe 4b Aufgabe 4c
|
|