gawk/Kontrollstrukturen

Aus Foxwiki


Kontrollstrukturen

  • Der Mustervergleich arbeitet über die Eingabedaten und regelte, ob für den aktuellen Datensatz Aktionen durchzuführen ist.
  • Die im weiteren vorgestellten Konstrukte gestatten den Kontrollfluss innerhalb einer solchen Aktionsfolge.

Bedingte Ausführung

if-else

Wohl jede Programmiersprache verfügt über ein if-else-Konstrukt, die Realisierung von awk orientiert sich an der C-Syntax:

if (Bedingung) {
# diese Aktionen
}
[ else {
# jene Aktionen
} ]
  • Evaluiert die Bedingung zu wahr (!=0), so werden die Aktionen des if -Zweigs ausgeführt, anderenfalls wird der optionale else -Zweig betreten.
  • Folgt einem Zweig nur eine einzelne Aktion, können die geschweiften Klammern entfallen.
  • Das nachfolgende Beispiel widerspricht eigentlich dem Einsatzzweck von Awk, bedarf es doch keinerlei Eingabedaten.
  • Es testet, ob das Skript mit (mind.) einem Argument aufgerufen wurde.
  • Fehlt dieses, endet das Skript mit einer Fehlerausgabe, anderenfalls wird der Wert des ersten Arguments potenziert:
$ cat potenz.awk
#!/usr/bin/awk -f

BEGIN {
if (ARGV[1] = "") {
print "Benutze: ./potenz.awk 'beliebiger_Wert'";
exit 1;
}
else {
print "x^x =", ARGV[1]**ARGV[1];
}
}
Anmerkung
Während der Abhandlung zu Variablen wurde erwähnt, dass nicht initialisierte Variablen intern mit »0« (numerischer Kontext) bzw. 
  • mit »""« (Zeichenkettenkontext) belegt werden.
  • Da »0« eine erlaubte Eingabe des Skripts darstellt, erzwingen wir mit dem Vergleich mit der leeren Zeichenkette letzteren Kontext.
  • Awk kennt kein zu case äquivalentes Konstrukt, sodass das zur Bewertung mehrerer Bedingungen verschachtelte if-else-Anweisungen verwendet werden:
if (Bedingung 1) {
# Aktionen
}
else if (Bedingung 2) {
# Aktionen
}
[...]
else {
# Aktionen
}
  • Bei mehreren erfüllten Bedingungen werden einzig die Aktionen der ersten zutreffenden ausgeführt.
  • Wird keine Bedingung wahr, werden alle Aktionen des optionalen else-Zweigs abgearbeitet.

Conditional-if

Manchmal soll einer Variable in Abhängigkeit vom Ergebnis einer Bedingung ein Wert zugewiesen werden.

Mit »if-else« wäre das folgende Fragment denkbar:

if (Bedingung)
variable = Wert_1
else
variable = Wert_2
  • Prägnanter ist die Schreibweise des Conditional-if:
  • variable = Bedingung ? Wert_1 :Wert_2
  • Es bleibt Ihnen überlassen, welche Varianten Sie wählen.
  • Dir letztere Schreibweise unterstreicht deutlicher das Ansinnen, einer Variable einen Wert zuzuweisen.

Da conditional-if im Gegensatz zu if-else einen Wert liefert, finden sich auch hin und wieder Situationen, wo eine Umschreibung per if-else umständlich, wenn nicht gar unmöglich ist:

$ awk 'BEGIN { x=1; while (x <= 3) printf("%d Osterei%s\n", x, x++>1 ?"er":"") }'
1 Osterei
2 Ostereier
3 Ostereier

printf wird im Abschnitt Ein/Ausgabe besprochen.

Schleifen

for

Die for-Schleife wird bevorzugt, wenn eine bekannte Anzahl Durchläufe der Anweisungen im Schleifenrumpf erfolgen soll:

for (Zähler initialisieren; Zähler testen; Zähler verändern) {
# Aktionen
}
  • Die geschweiften Klammern dürfen entfallen, wenn nur eine einzelne Aktion zum Schleifenrumpf gehört.
  • Die mit Zähler initialisieren, Zähler testen und Zähler verändern bezeichneten Ausdrücke beschreiben den »gebräuchlichen« Verwendungszweck.
  • Wie auch in C wird der erste Ausdruck (Zähler initialisieren) einmalig vor Eintritt in die Schleife ausgeführt.

Der zweite Ausdruck (Zähler testen) wird jeweils vor dem nächsten Durchlauf der Schleife betrachtet und der dritte Ausdruck (Zähler verändern) wird nach Bearbeitung der Anweisung des Schleifenrumpfes berechnet:

$ awk 'BEGIN {for ( i=0; i<3; i++) print i;}'
0
1
2
$ awk 'BEGIN {for ( i=0; i++<3; ) print i;}'
1
2
3
  • Die Beispiele zeigen auch, dass die Angabe der Ausdrücke optional ist.

Analog zu C kann eine Endlosschleife wie folgt angegeben werden:

$ awk 'BEGIN {for (;;) printf(".") }'
  • Was Awk im Gegensatz zu C allerdings nicht gestattet, ist die Angabe einer kommaseparierten Liste von Ausdrücken (»for (i=0,j=0;...;...)«).

while

while -Schleifen werden bevorzugt, wenn die Anzahl der Schleifendurchläufe vom Ergebnis eines Ausdrucks abhängt.

while (Bedingung) {
# Aktionen
}
  • Die geschweiften Klammern dürfen entfallen, wenn nur eine einzelne Aktion zum Schleifenrumpf gehört.

Das folgende Beispiel berechnet die Fakultät zu einer per Argument übergebenen Zahl:

$ cat fakultaet.awk
#!/usr/bin/awk -f

BEGIN {
if (ARGC < 2 || (ARGV[1] !~ /^[0-9]+$/)){
print "Aufruf: ./fakultaet.awk <Zahl>";
exit 1;
}

fakultaet=1;
zahl=ARGV[1];

while (zahl > 1)
fakultaet*=zahl--;

print "Fakultaet von", ARGV[1], "ist", fakultaet;
}
$ ./fakultaet.awk 5
Fakultaet von 5 ist 120

do-while

In Situationen, in denen ein Programmabschnitt mindestens einmal - und in Abhängigkeit von einer Bedingung weitere Male - zu durchlaufen ist, bietet sich die do-while -Schleife an:

do {
# Aktionen
} while (Bedingung)

Eine Anwendung könnte der Test einer Nutzereingabe sein, die solange zu wiederholen ist, bis sie dem geforderten Format entspricht:

do {
printf("Geben Sie eine Zahl ein: ");
getline zahl < "-";
} while ( zahl !~ /^digit:+$/ )

getline wird im Abschnitt Ein/Ausgabe behandelt.

Weitere Kontrollanweisungen

  • Betrachtet man das Hauptprogramm von Awk als eine Schleife (die über alle Zeilen der Eingabe läuft), so besitzen die nachfolgend vorgestellten Anweisungen eine Gemeinsamkeit: Sie verändern den Kontrollfluss von Schleifen.* break und continue wirken mit for und [do-]while zusammen
  • exit, next und nextfile betreffen die Hauptschleife.

break

  • Mit break kann eine for-, while- oder do-while-Schleife vorzeitig verlassen werden.

Die Programmausführung fährt mit der der Schleife unmittelbar folgenden Anweisung fort.

$ awk 'BEGIN { for (;;) if (x++ = 5) break; print x}'
6

continue

  • Wird continue innerhalb einer for-, while- oder do-while-Schleife ausgeführt, wird die Bearbeitung des aktuellen Schleifendurchlaufs abgebrochen und der nächste Durchlauf begonnen.
$ awk 'BEGIN { for (i=1;i<10;i++) {if (i%2) continue; print i } }'
2
4
6
8

exit

  • Der exit -Befehl dient zum (vorzeitigen) Beenden der Hauptschleife von Awk.
  • Das Programm wird unverzüglich mit Ausführung des optionalen END-Statements fortgeführt.
  • Als Argument kann exit ein Ausdruck mitgegeben werden.
  • Der Wert des Ausdrucks ist der Rückgabewert von Awk.
  • Ohne Angabe des Arguments wird implizit 0 angenommen.
  • Eine diesbezügliche Ausnahme bildet die Verwendung von exit innerhalb der END-Anweisungen.

Fehlt hier das Argument, gilt ein in der Hauptschleife (bzw. innerhalb von BEGIN) gesetzter Wert:

$ awk 'BEGIN { exit 3 }; END { exit }'; echo $?
3
$ awk 'BEGIN { exit 3 }; END { exit 0 }'; echo $?
0

next

next wirkt wie continue, nur dass jetzt der aktuelle Durchlauf des Hauptprogramms unterbrochen und mit dem nächsten Durchlauf - sprich: mit der nächsten Zeile der Eingabe - fortgefahren wird.

nextfile

  • Diese Erweiterung von GNU-Awk (nicht POSIX) wirkt wie next, d.h.
  • es wird zum Beginn des Hauptprogramms gesprungen.
  • Die aktuelle Datei wird geschlossen und als Datensatz die erste Zeile der nächsten Eingabedatei geladen.