4.4 awk
Bei awk handelt es sich um eine Programmiersprache für deren Anwendung sich die Autoren, die sie beschreiben wollen, immer interessante Beispiele für deren Anwendung ausdenken. In [Herold03A] werden beispielsweise Lebensmitteltabellen und Bundesliegaergebnisse ausgewertet, in [VoReJo97A] begnügt man sich mit einer Nummernliste, die nach Telefonnummern aussieht, und in unserem Buch »Einstieg in Linux« ([WendPloe04A]) sind es Wohnorte und Benutzer-IDs. Mal sehen, was wir diesmal nehmen.
Die drei Zeichen, aus denen der Name des Programms besteht, leiten sich von den Namen derer ab, die awk (den awk-Interpreter) programmierten:
Alfred V. Aho, Peter J. Weinberger und Brian W. Kernighan. Diese drei schrieben übrigens auch ein Buch ([AhWeKe88A]) über awk.
Doch mittlerweile gibt es neuere Bücher zu dieser Sprache, etwa [Herold03A] oder ganz einfach das vorliegende Buch – nach dem Lesen (und Verstehen) dieses Unterkapitels werden Sie das für den täglichen Umgang mit awk Wichtige wissen. Ein vollständiges Buch zur awk-Programmiersprache ersetzt es jedoch nicht.
Bei OpenBSD-Systemen finden Sie ein weiteres awk-Buch der Autoren im Verzeichnis /usr/share/doc/usd/16.awk. Lassen Sie dort make durchlaufen, was die Datei paper.ps erzeugt, die Sie beispielsweise mit GhostView (gv) unter X11 ansehen können.
4.4.1 Nutzen und Interpreter
Die Programmiersprache dient, ähnlich wie sed, zum Auseinandernehmen und Verarbeiten von Streams. Jedoch bietet awk Ihnen weitaus umfangreichere Möglichkeiten. Es handelt sich dabei schließlich um eine ganze Programmiersprache. Solch eine Skriptsprache benötigt natürlich auch einen Interpreter, der die Anweisungen im Code einliest und ausführt. Dieser Interpreter nennt sich schlicht awk. awk ist die älteste Interpreter-Implementierung von awk, es gibt noch neuere Versionen wie nawk (u.a. BSD) und gawk von GNU. In diesem Buch arbeiten wir mit der Variante (n)awk.
Die Syntax von awk ist sehr stark an die Programmiersprache C angelehnt, zudem ist die Sprache äußerst einfach zu erlernen – bereits mit wenigen Zeilen Code kann ein komplexes Problem gelöst werden, für das man in Sprachen wie C einige hundert Zeilen Quellcode benötigen würde. <Allerdings sind interpretierte Sprachen dafür auch viel langsamer als ein in eine Binärdatei übersetztes C-Programm. Eine gute Ausnahme stellt Common-Lisp dar, das auch ohne Bytecode-Übersetzung relativ schnell läuft.>
4.4.2 Der Aufruf von awk
Ein awk-Aufruf setzt sich aus mehreren Parametern zusammen, die teilweise optional sind.
$ awk [Ausdruck] [{ Anweisungen }] [Datei]
Listing 4.21 awk-Aufrufschema
Ausdruck
Der erste Parameter ist ein regulärer Ausdruck. Dieser Ausdruck muss nicht immer übergeben werden. Da awk, wie auch sed, den Input-Stream zeilenweise durcharbeitet, kann durch den Ausdruck-Parameter jedoch eine Filterung realisiert werden. In englischen Büchern nennt man diesen Ausdruck oft »Pattern«, in einigen deutschsprachigen Büchern aber auch »Muster« – gemeint ist immer das Gleiche: der reguläre Ausdruck.
Anweisungen
Den zweiten Parameter stellen die awk-Anweisungen – der eigentliche Skriptcode – dar. Diese Anweisungen legen fest, welche Manipulationen am Input-Stream durchgeführt werden sollen. Wichtig ist dabei, dass diese Anweisungen in geschweifte Klammern eingebettet werden. Auch der Anweisungen-Parameter muss nicht immer übergeben werden.
Datei
Die Datei legt die Datei fest, aus der der Input-Stream gelesen werden soll. Sie müssen auch diesen Parameter nicht angeben – awk liest in diesem Fall von der Standardeingabe oder aus einer Pipe.
Wie Sie sehen, scheinen alle awk-Parameter optionaler Natur zu sein, doch dies stimmt nicht ganz: Es muss immer entweder ein Pattern oder eine Aktion (oder beides) angegeben werden, ganz ohne Pattern und Aktion verweigert awk den Dienst.
Zudem muss ein Input-Stream vorhanden sein, dabei ist es jedoch egal, ob dieser nun aus einer angegebenen Datei oder einer Pipe gelesen wird.
4.4.3 Erste Gehversuche
Reguläre Ausdrücke
Testen wir doch einmal das bisher Gelernte, nämlich reguläre Ausdrücke im Zusammenhang mit awk. Dabei werden wir zunächst einmal nur einen regulären Ausdruck, aber keine awk-Anweisungen übergeben. Als Input-Stream soll dabei die Datei /etc/group dienen.
Um den kompletten Inhalt der Datei auszugeben, muss eigentlich nur ein regulärer Ausdruck angegeben werden, der zwangsweise auf alle Zeilen in der Input-Datei zutrifft. Auf den ersten Blick bietet sich dabei der Ausdruck ».« an. Im Falle der Datei /etc/group mag dies auch funktionieren, da so jede ausgegeben wird Zeile in der ein beliebiges Zeichen enthalten ist.
Sofern allerdings eine Leerzeile in einer Datei vorkommt, würde dies nicht mehr funktionieren. Dieses Problem kann umgangen werden, indem man ein beliebig häufiges Vorkommen eines beliebigen Zeichens als regulären Ausdruck angibt:
$ awk '/(.)*/' /etc/group
wheel:*:0:root,cdp_xe
daemon:*:1:daemon
kmem:*:2:root
sys:*:3:root
tty:*:4:root
operator:*:5:root
bin:*:7:
news:*:8:
wsrc:*:9:
users:*:10:
...
Listing 4.22 awk gibt eine Datei aus.
Möchten wir nun alle Zeilen herausfiltern, in denen ein »n« enthalten ist, geht auch dies völlig problemlos:
$ awk '/n/' /etc/group
daemon:*:1:daemon
bin:*:7:
news:*:8:
_identd:*:29:
_fingerd:*:33:
_sshagnt:*:34:
_kadmin:*:60:
_token:*:64:
crontab:*:66:
network:*:69:
Listing 4.23 awk filtert nach »n«.
Wie Sie sehen, kann awk (wie es bereits bei sed der Fall war) auf diese Weise die (Grund)Aufgaben des Programms grep übernehmen.
Anweisungen
Lässt man nun den regulären Ausdruck weg und verwendet an seiner Stelle eine einfache Anweisung, kann man ebenfalls den Dateiinhalt ausgeben. Da nun kein Filter (eben durch einen regulären Ausdruck) vorgegeben ist, werden alle Zeilen des Input-Streams an die Anweisungen zur Verarbeitung weitergegeben. Nun müssen diese Zeilen nur noch durch eine entsprechende Ausgabe-Anweisung auf dem Bildschirm ausgegeben werden. Dazu verwenden wir die Anweisung print.
$ awk '{print\' /etc/group}
wheel:*:0:root,cdp_xe
daemon:*:1:daemon
kmem:*:2:root
sys:*:3:root
tty:*:4:root
operator:*:5:root
bin:*:7:
news:*:8:
wsrc:*:9:
users:*:10:
...
Listing 4.24 awk mit Anweisungen
Nun beides zusammen
Nun sind wir so weit, dass wir beide Parameter, nämlich den des regulären Ausdrucks und den der Anweisungen, kombinieren können. Das hierfür verwendete Beispiel ist nicht sonderlich sinnvoll, verdeutlicht jedoch sehr einfach die Funktionsweise von awk.
Hierzu lassen wir den regulären Ausdruck alle Zeilen herausfiltern, in denen ein »x« enthalten ist. Diese Zeilen werden an den Anweisungsblock weitergereicht. Da der Anweisungsblock nur die Anweisung print enthält, werden alle gefilterten Zeilen auf dem Bildschirm ausgegeben.
$ awk '/x/ {print\' /etc/group}
wheel:*:0:root,cdp_xe
_x11:*:35:
proxy:*:71:
cdp_xe:*:1000:
Listing 4.25 Regulärer Ausdruck und eine Anweisung
4.4.4 Der Anweisungsblock
Im Anweisungsblock – also in dem Teil, der in zwei geschweifte Klammern eingebettet wird – sind ein paar Regeln zu beachten.
Anweisungen separieren
In awk können Anweisungen nicht einfach hintereinandergeschrieben werden. Damit die Shell weiß, wo eine Anweisung endet und eine neue beginnt, muss – wie in der Shell – eine Separierung der Anweisungen erfolgen. Auch in awk wird diese Separierung durch ein Semikolon (;) realisiert. Außerdem können Anweisungen durch Zeilen separiert werden.
{ Anweisung1 Anweisung2 Anweisung3 Anweisung4 // Fehler! Anweisung3 ; Anweisung4 // Richtig! }
Listing 4.26 Anweisungen
Eine weitere Möglichkeit
Neben der Separierung durch ein Semikolon ist es noch möglich, Anweisungen durch geschweifte Klammern zu separieren.
Dies wird bei bedingten Anweisungen verwendet, funktioniert aber auch außerhalb. Allerdings gehört die Verwendung von geschweiften Klammern außerhalb von bedingten Anweisungen zum schlechten (weil unübersichtlichen)
Programmierstil und wird daher nur der Vollständigkeit halber erwähnt.
{ { Anw1 } Anw2 { Anw3 } Anw4 { Anw5 } Anw6 }
Listing 4.27 Anweisungen mit {}
BEGIN und END
Bisher wissen Sie nur, dass es so etwas wie einen Anweisungsblock gibt und dass in diesen die Anweisungen hineingepackt werden. In dem Anweisungsblock werden alle Anweisungen nacheinander ausgeführt, was allerdings nicht immer so einfach ausreicht.
Der Hauptanweisungsblock wird für jede Zeile erneut ausgeführt. Was aber tut man, wenn man vor der Bearbeitung der einzelnen Zeilen einige Anweisungen von awk ausführen lassen möchte? Und was tut man, wenn man möchte, dass, nachdem alle Eingabezeilen verarbeitet worden sind, noch weitere Anweisungen ausgeführt werden?
Die Antwort auf diese Fragen liefert die Unterteilung der Anweisungsblöcke in drei Bereiche: den Anfangsteil, den Hauptteil und den Endteil. Man könnte auch von einer aufsatzähnlichen Einteilung in Einleitung, Hauptteil und Schluss sprechen, falls Sie es sich anhand dieser Analogie einfacher merken können.
Der Anfangsteil wird durch das Schlüsselwort BEGIN eingeleitet, der Endteil durch das Schlüsselwort END.
Der Hauptteil benötigt kein Schlüsselwort und wird, wie bereits bekannt, einfach durch geschweifte Klammern begrenzt. Diese Klammern werden auch zur Begrenzung der BEGIN- und END-Blöcke verwendet. Somit ergibt sich der folgende schematische Aufbau eines awk-Skripts:
BEGIN { Anweisung1; Anweisung2; ... AnweisungN; } { Anweisung1; ... AnweisungN; } END { Anweisung1; Anweisung2; ... AnweisungN; }
Listing 4.28 Der Aufbau eines awk-Skripts
Nehmen wir einmal an, es soll eine Datei mit drei Zeilen verarbeitet werden und vor und nach der Verarbeitung ein bestimmter Text ausgegeben werden. Diese Textausgabe wird mit der print-Anweisung umgesetzt, die wir im Laufe des Kapitels noch näher betrachten werden. Dabei ist zu beachten, dass wir den auszugebenden Text in Anführungszeichen geschrieben haben.
$ awk ' BEGIN { print "Es folgt der Dateiinhalt:" } { print } END { print "Das Ende der Datei ist erreicht." print "Tschüss!" \ ' /tmp/Inputdatei}
Listing 4.29 END und BEGIN angewandt
Wenn /tmp/Inputdatei den Inhalt
zeile1 zeile2 zeile3
Listing 4.30 /tmp/Inputdatei
hat, ergibt sich beim Ausführen des Befehls die folgende Ausgabe:
Es folgt der Dateiinhalt: zeile1 zeile2 zeile3 Das Ende der Datei ist erreicht. Tschüss!
Listing 4.31 Die Ausgabe des awk-Aufrufs
Kommentare
Um Kommentare in einem awk-Skript unterzubringen, verwendet man das Rauten-Zeichen (#). Alles, was hinter diesem Zeichen steht, wird vom Interpreter als Kommentar interpretiert und nicht weiter beachtet. Kommentare bieten Ihnen die Möglichkeit, Ihre Skripts übersichtlicher zu gestalten und komplizierte Anweisungsabschnitte zu kommentieren.
Besonders, wenn man nach einigen Monaten oder gar Jahren noch einmal etwas an einem alten awk-Skript verändern möchte (oder muss), wird man sich darüber freuen, dass man komplizierte Stellen im Skriptcode mit Kommentaren versehen hat.
{ # Spalte 3 enthält den Benutzernamen print $3 }
Listing 4.32 Ein simpler Beispielkommentar
Lange Zeilen
Manchmal, etwa bei langen Berechnungsformeln, kommen sehr lange Zeilen zustande. Lange Zeilen lassen sich jedoch je nach Editor relativ schlecht editieren und sind unübersichtlich. awk bietet die Möglichkeit, diese langen Zeilen auf mehrere kleine aufzuteilen, wobei man einfach einen Backslash (\) an das Ende einer Zeile stellt, die in der nächsten Zeile fortgesetzt werden soll.
# Dies geht nicht. Die zweite Zeile würde als # eigene Anweisung interpretiert werden und im # awk-Interpreter einen Fehler verursachen: print "Dies ist ein Text. Und hier ist" "noch ein Wert:" # So ist es richtig: print "Dies ist ein Text. Und hier ist" \ "noch ein Wert:"
Listing 4.33 Anwenden des Backslashs
4.4.5 Variablen
Eine Variable ist ein transparentes Mittel, um auf eine Adresse im Speicherbereich zuzugreifen. Dabei gibt man einer Variable einen Namen. Über diesen Namen kann man immer wieder auf diesen Speicherbereich zugreifen und die darin enthaltenen Daten manipulieren. Bei diesen Daten kann es sich sowohl um eine Zahl als auch um einen oder mehrere Buchstaben oder auch um eine Kombination aus Zahlen, großen und kleinen Buchstaben und Sonderzeichen, etwa einem $, handeln.
In awk wird dabei zwischen einer Variable, die nur aus Zahlen besteht (mit denen sich rechnen beziehungsweise vergleichen lässt), und einem so genannten String unterschieden, dem man neben Zahlen eben auch Buchstaben und Sonderzeichen zuweisen kann.
Der Name einer Variable sollte dabei nur aus Ziffern, Buchstaben und Unterstrichen bestehen. Dabei ist jedoch zu beachten, dass das erste Zeichen im Namen keine Ziffer ist. Gültige Variablennamen sind also beispielsweise »katze«, »katze2«, »_katze« oder »_123KaTzE321_«. Ungültig wären hingegen: »123katze«, »&katze« oder »#Katze«, wobei Letzteres als Kommentar gewertet werden würde.
Zudem sollten Variablen keine Namen von Builtin-Funktionen wie print oder printf tragen, da dies zu Problemen führt. Diese Builtin-Funktionen müssen Sie allerdings noch nicht zu diesem Zeitpunkt kennen, wir werden sie jedoch im weiteren Verlauf dieses Kapitels noch besprechen.
Variablen deklarieren und initialisieren
Eine Variable wird deklariert, indem man ihren Namen im awk-Skript einfügt. Dadurch weiß awk zumindest schon einmal, dass es eine Variable mit diesem Namen gibt. Über den Speicherbereich, der dieser Variable zugewiesen wird, müssen Sie sich übrigens nicht kümmern, dies erfolgt nämlich völlig transparent.
Die Initialisierung einer Variable, also die Zuweisung eines Wertes, wird durch das Gleichheitszeichen (=) realisiert. Dies geschieht in der Form variable=Wert und funktioniert sowohl mit Zahlen als auch mit ganzen Strings:
BEGIN { # Der Name einer Katze sei Felix, KatzenName="Felix" # ihr Wohnort sei Ettenbeuren. Wohnort="12345 Ettenbeuren" # Die Hausnummer hingegen sei 123. Hausnummer=123 }
Listing 4.34 Variablen deklarieren und initialisieren
Werte manipulieren
Die Werte von Variablen kann man auf verschiedene Arten manipulieren. Entweder weist man einen komplett neuen Wert durch das Gleichheitszeichen zu oder manipuliert auf Basis des bisherigen. Bei der Manipulation ist zu unterscheiden, ob man Zahlenwerte oder Strings manipuliert. Mit Zahlenwerten können Rechenoperationen durchgeführt werden, bei Strings geht es um die Manipulation von Zeichen.
KatzenName="Felix" # Nun wird der alte Wert verworfen und durch # "Mauzi" ersetzt KatzenName="Mauzi"
Listing 4.35 Erneute Wertzuweisung durch =
Zahlenwerte manipulieren
Um zunächst einmal grundlegende Rechenoperationen durchführen zu können, muss man Zahlenwerte manipulierennn können.
Zum Rechnen sind nicht unbedingt Variablen notwendig, man kann auch direkt rechnen und das Ergebnis einer Berechnung ausgeben lassen. Jedoch ist es oftmals sehr sinnvoll, ein Ergebnis oder die Zahlen, die in eine Rechnung einfließen, in Variablen zu packen. Das macht die Programmierung einfacher und die Programmstruktur übersichtlicher, dynamischer und verständlicher.
Nehmen wir zur Erläuterung dieses Satzes einmal folgende Situation: Wir wollen eine Rechnung durchführen, bei der der Wert einer Eingabe mit einer aktuellen Prozentzahl und einigen weiteren Werten verrechnet werden soll. Dies könnte etwa so aussehen:
{ neuwert = $1 * 104 + 49 – ( 12 * 13 ) + ( 12 / 4 ) }
Und nehmen wir weiterhin an, jeder dieser Werte ist dynamisch und muss eventuell ständig angepasst werden. Da wäre es doch viel einfacher, wenn man den einzelnen Werten sinnvolle Variablennamen geben würde, was in den Code beispielsweise folgendermaßen implementiert werden könnte:
{ Prozentsatz = 104 Zuschuss = 49 AnzahlBroetchen = 12 Preis = 13 AnzahlKartoffeln = 12 Personen = 4 neuwert = $1 * Prozentsatz + Zuschuss – \ ( AnzahlBroetchen * Preis ) + \ ( AnzahlKartoffeln / Personen ); print neuwert }
Doch welche Möglichkeiten stehen einem beim Rechnen mit awk eigentlich zur Verfügung? Zum einen sind dies diverse Operatoren und zum anderen Builtin Funktionen. Im Folgenden werden die Operatoren beschrieben, die Builtin-Funktionen werden später in einem eigenen Abschnitt erläutert.
+ – * / ^
Die grundlegenden Rechenoperationen gehen bereits aus dem vorherigen Listing hervor. Dabei handelt es sich um Addition (+), Subtraktion (-), Division (/) und Multiplikation (*). Das Dach-Zeichen (^) dient zur Angabe eines Exponenten, 2^8 ergäbe beispielsweise 256. Des Weiteren können Klammern verwendet werden.
Modulo
Das Modulo-Zeichen (%) führt eine Division durch und gibt den Rest dieser Division zurück. Die Anweisung 10%3 würde beispielsweise den Wert »1« ergeben.
+= -= /= *= ^= %=
awk stellt noch eine weitere Möglichkeit bereit, um die eben genannten Rechenoperationen durchzuführen. Diese hat allerdings nur den Sinn, den Code übersichtlicher und kürzer zu gestalten. Dabei können Rechenoperationen verkürzt werden, die abhängig vom Wert einer Variable derselben Variable einen neuen Wert zuweisen. So kann man den Code-Ausschnitt
var = var + 1
Listing 4.36 Lange Form
auch in der kurzen Form
var += 1
Listing 4.37 Kurze Form
schreiben. Dies funktioniert mit der Addition, Subtraktion, Division, Multiplikation, Modulo und dem Exponenten-Operator.
++ --
Doch awk kann noch mehr: nämlich in- und dekrementieren. Dabei wird der Zahlenwert einer Variable um den Wert 1 erhöht
(Inkrementierung) bzw. veringert (Dekrementierung). Die Inkrementierung wird durch das doppelte Plus-Zeichen, die Dekrementierung durch ein doppeltes Minus-Zeichen angewandt. Diese beiden Möglichkeiten der Wertmanipulation sind besonders in Schleifen von großer Bedeutung, zudem verkürzen sie den Code. Denn die Anweisung
Personen = Personen – 1;
Listing 4.38 Dekrementierungsbeispiel
kann durch die Dekrementierung verkürzt als
Personen--;
Listing 4.39 Dekrementierung
geschrieben werden, was umgekehrt natürlich auch für die Inkrementierung gilt.
Vorher oder nacher?
Bei der In- und Dekrementierung ist allerdings zwischen der Prä- und Post-Variante zu unterscheiden. Was bedeutet dies? Nun, um es nicht unnötig kompliziert zu formulieren: Wird der In- bzw. Dekrementierungsoperator vor eine Variable gestellt (das ist die Prä-Variante), wird ihr Wert vor der Durchführung einer Anweisung verändert; steht der Operator hingegen hinter einer Variable (das ist die Post-Variante), wird erst die Anweisung und dann die Wertveränderung durchgeführt. Das folgende Beispiel verdeutlicht dies:
BEGIN { Personen = 2; # gibt '2' aus: print Personen; # gibt '3' aus: print ++Personen; # gibt auch '3' aus: print Personen--; # gibt '1' aus: print --Personen; }
Listing 4.40 Vorher oder nacher?
Interpretervariablen
awk kennt neben den Variablen, die Sie selbst erstellen können, auch sogenannte Builtin-Variablen. Diese Builtin-Variablen haben vordefinierte Namen, die alle großgeschrieben sind. Diese Variablen werden genauso verwendet wie die herkömmlichen Variablen.
Die von Ihrem Interpreter unterstützten Variablen finden Sie in der zugehören Manpage. Hier ist eine Liste der von jedem Interpreter unterstützten Interpretervariablen sowie deren Nutzen:
- $0
- In dieser Variable steht der komplette Inhalt einer eingelesenen Zeile.
- $n
- (Dabei steht n für eine Zahl größer null.) In $1 ... $n sind die einzelnen Spalteninhalte einer eingelesenen Zeile gespeichert. Dies zu wissen ist besonders wichtig, da Sie fast immer auf diese Variablen zurückgreifen müssen. Hier ein kleines Anwendungsbeispiel zur Verdeutlichung:
$ cat /tmp/myfile root 0 /root swendzel 1000 /home/swendzel $ awk '{ print "Benutzername: " $1 "\tUser-ID: " $2 "\tHomedir: " $3 \' /tmp/myfile} Benutzername: root User-ID: 0 Homedir: \ /root Benutzername: swendzel User-ID: 1000 Homedir: \ /home/swendzelListing 4.41 $n anwenden
- ARGC
- (argument count) ARGC enthält die Anzahl der awk übergebenen Argumente.
- ARGV
- (argument vector) ARGV ist ein Array und enthält die übergebenen Argumente selbst.
- CONVFMT
- (converting format) Diese Variable legt das Format für die Konvertierung von Zahlenwerten aus Variablen in Strings fest. Diese Variable ist standardmäßig auf den Wert »%.6g« gesetzt. Dies bedeutet, dass die ersten sechs Nachkommastellen hinter dem Komma in einen String übernommen werden. Dies lässt sich jedoch ändern, wodurch Ihnen eine äußerst genaue Ausgabe von Kommawerten zur Verfügung steht:
$ awk 'BEGIN { print "1 / 3 = " 1/3 CONVFMT="%.15g"; print "1 / 3 = " 1/3 \'} 1 / 3 = 0.333333 1 / 3 = 0.333333333333333Listing 4.42 Verändern von CONVFMT
- ENVIRON
- (environment) ENVIRON ist ein Array, in dem die Umgebungsvariablen der Shell enthalten sind. Die jeweiligen Index-Elemente des Arrays enthalten dabei den zugehörigen Wert der jeweiligen Variablen.
$ awk 'BEGIN { print "Terminal: " ENVIRON["TERM"]; print "Mailqueue: " ENVIRON["MQUEUE"]; \'} Terminal: xterm-color Mailqueue: /var/spool/mqueueListing 4.43 ENVIRON nutzen
- FILENAME
- In dieser Interpretervariable ist der Name der Datei gespeichert, die derzeit als Input dient. Sofern der Interpreter die Eingabedatei wechselt, wird auch der Wert von FILENAME neu gesetzt.
- FNR
- (file number records) In dieser Variable ist die aktuelle Anzahl der bisher verarbeiteten Eingabezeilen (= records) gespeichert.
$ awk '{ print FNR \' /etc/passwd} 1 2 3 4 5 ...
Listing 4.44 FNR
- FS
- (field separator) Diese Variable ist von großer Bedeutung. Sie legt das Zeichen fest, das zur Trennung von einzelnen Spalten in der Eingabedatei dient. Normalerweise wird hierfür das Tab- und Newline-Zeichen verwendet. Diese Variable kann übrigens auch durch den Parameter -Fx beim awk-Aufruf gesetzt werden, wobei »x« das Separierungszeichen ist.
$ awk -F: '{ print "User: " $1 "\tShell: " $7 \' /etc/passwd} User: root Shell: /usr/local/bin/zsh User: daemon Shell: /sbin/nologin User: operator Shell: /sbin/nologin ...Listing 4.45 Aufteilen der passwd
- NF
- (number of fields) In dieser Variable, die für jede Eingabezeile neu gesetzt wird, steht die aktuelle Anzahl von Spalten der jeweiligen Zeile. Dies ist besonders bei Eingabedateien von Nutzen, bei denen die Anzahl der Spalten von Zeile zu Zeile variiert. Ein üblicher Vertreter solcher Dateien ist /etc/services.
$ awk '{ print NF \' /etc/services} 2 4 3 2
Listing 4.46 NF in /etc/services
- NR
- (number of records) NR enthält die aktuelle Anzahl der bereits verarbeiteten Eingabezeilen.
$ cat /tmp/file1 zeile1 zeile2 zeile3 $ cat /tmp/file hier steht auch etwas drin ;-) $ awk '{ print NR \' /tmp/file[12]} 1 2 3 4 5 6Listing 4.47 NR funktioniert auch über mehrere Dateien.
- OFMT
- (output format) Diese Variable hat eine ähnliche Wirkung wie CONVFMT. Hierbei wird jedoch nicht geregelt, wie Zahlen in Strings, sondern wie Zahlen in der direkten Ausgabe umgewandelt werden sollen. Ein Beispiel soll diesen Unterschied verdeutlichen:
$ awk 'BEGIN { CONVFMT="%.14g" X=1.1234567890123456 print X \'} 1.12346 $ awk 'BEGIN { OFMT="%.14g" X=1.1234567890123456 print X \'} 1.1234567890123Listing 4.48 CONVFMT im Vergleich zu OFMT
- OFS
- (output field separator) Diese Variable funktioniert analog zur Variable FS. Nur ist OFS nicht für die Separierung der Eingabespalten, sondern für die Separierung der Ausgabespalten zuständig.
- ORS
- (output record separator) Dieses Feld separiert die einzelnen Zeilen bei der Ausgabe. Standardmäßig ist dieser Variable das Newline-Zeichen (\n) zugewiesen.
- RLENGTH
- (regular expression length) RLENGTH gibt die Länge des regulären Ausdrucks an, der durch die Funktion match() gefunden wurde.
- RS
- (input record separator) Der Wert dieser Variable legt das Zeichen fest, das die einzelnen Eingabezeilen separiert. Normalerweise ist dies das Newline-Zeichen.
- RSTART
- (regular expression start) Diese Variable enthält den Wert der Anfangsposition des regulären Ausdrucks im String, der der match()-Funktion übergeben wurde.
- SUBSEP
- (subscript separator) Der Wert von SUBSEP legt das Separierungszeichen der einzelnen Array-Elemente fest. In der Regel muss der Inhalt dieser Variable nicht verändert werden.
4.4.6 Arrays
Neben normalen Variablen gibt es in awk auch noch sogenannte Arrays. Als einen Array kann man sich eine ganze Reihe von Variablen vorstellen. Am besten verdeutlicht man die Funktionsweise von Arrays anhand eines Beispiels.
Nehmen wir einmal an, es gibt drei Katzen. Allen diesen Katzen soll ein bestimmtes Alter zugewiesen werden. Dies kann mithilfe von Arrays in awk sehr simpel realisiert werden. Wir legen ein Array mit drei Elementen an. Dabei steht jedes Element für eine Katze. Diesen Elementen (also quasi den einzelnen Variablen des Arrays) weisen wir jeweils einen Wert – das Alter – zu. Unser Array hat dabei wie eine Variable einen einfachen Namen – MyArray – bekommen.
$ awk 'BEGIN { MyArray[1]=3; MyArray[2]=8; MyArray[3]=3; print "Felix ist " MyArray[1] " Jahre alt."; print "Mauzi ist " MyArray[2] " Jahre alt."; print "Schröder ist " MyArray[3] " Jahre alt."; }' Felix ist 3 Jahre alt. Mauzi ist 8 Jahre alt. Schröder ist 3 Jahre alt.
Listing 4.49 Arrays in awk
Assoziative Arrays
Da awk auch sogenannte assoziative Arrays unterstützt, muss nicht durch Index-Nummern auf die Elemente zugegriffen werden, nein, man kann die Elemente benennen. Wir benennen diese Elemente im Folgenden jeweils nach dem Namen der jeweiligen Katze. Dies erleichtert das Arbeiten mit Arrays sehr, da man sich nicht mit den Nummern von Array-Elementen herumschlagen muss.
$ awk 'BEGIN { MyArray["Felix"]=3; MyArray["Mauzi"]=8; MyArray["Schröder"]=3; print "Felix ist " MyArray["Felix"] " Jahre alt."; print "Mauzi ist " MyArray["Mauzi"] " Jahre alt."; print "Schröder ist " MyArray["Schröder"] \ " Jahre alt."; \'} Felix ist 3 Jahre alt. Mauzi ist 8 Jahre alt. Schröder ist 3 Jahre alt.
Listing 4.50 Assoziative Arrays in awk
Bei awk-Arrays wird der Element-Index in eckigen Klammern angegeben. Dies kann eine Zahl oder ein Assoziativwert, etwa ein String, sein. Einen Assoziativwert muss man dabei in Anführungszeichen schreiben. Einem Array-Element weist man, wie auch einer Variable, durch ein Gleichheitszeichen einen Wert zu.
in
Gehen wir nun noch einen Schritt weiter. Dazu verwenden wir den Operator in. Diesen bauen wir in eine sogenannte for-Schleife ein. <Schleifen werden in Kürze behandelt. Hier reicht es allerdings erst einmal aus, dass Sie wissen, dass die for-Schleife so lange die nachstehende Anweisung ausführt, bis alle Array-Elemente durchgearbeitet worden sind.>
Diese Schleife geht in diesem Fall durch den in-Operator jedes Array-Element durch, das im Array MyArray existiert.
in weist dabei den Namen eines Elements der Variable i zu.
$ awk 'BEGIN { MyArray["Felix"]=3; MyArray["Mauzi"]=8; MyArray["Schröder"]=3; # 'i' selbst ist nun der Name # MyArray[i] ist der zugehörige Wert for (i in MyArray) print i " ist " MyArray[i] " Jahre alt."; \'} Mauzi ist 8 Jahre alt. Schröder ist 3 Jahre alt. Felix ist 3 Jahre alt.
Listing 4.51 in-Operator und for-Schleife
delete
Wenn nun eine dieser Katzen verstirbt (was natürlich nicht schön wäre), müsste man sie aus dem Array entfernen.
Und natürlich können in awk auch irgendwie irgendwelche Elemente irgendeines Arrays entfernt werden. Dies geht sogar sehr einfach:
mit der delete-Anweisung.
$ awk 'BEGIN { MyArray["Felix"]=3; MyArray["Mauzi"]=8; MyArray["Schröder"]=3; delete MyArray["Mauzi"]; for (i in MyArray) print i " ist " MyArray[i] " Jahre alt."; \'} Schröder ist 3 Jahre alt. Felix ist 3 Jahre alt.
Listing 4.52 in-Operator und for-Schleife
4.4.7 Bedingte Anweisungen
Eigentlich wollte ich dieses Unterkapitel mit dem Satz »Eine bedingte Anweisung – darunter versteht man eine Anweisung, die bedingt ausgeführt wird.« einleiten. Ich hoffe dieser Satz hat wenigstens etwas Erheiterndes für Sie an sich – ich finde ihn toll.
Eine bedingte Anweisung besteht aus zwei Komponenten: der Bedingung selbst – sie ist eine Wertabfrage, etwa von einer Variable – und den Anweisungen bzw. Anweisungsblöcken. Davon gibt es oftmals sogar zwei: einen für den Fall, dass die Bedingung nicht erfüllt ist, und einen für den Fall, dass die Bedingung erfüllt ist.
Die primäre Möglichkeit, eine bedingte Anweisung zu verwenden, besteht in der if-Anweisung. Diese Anweisung wird in der folgenden Form in ein awk-Skript implementiert:
if ( Bedingung ) { Anweisung1; Anweisung2; }
Listing 4.53 Implementierung von if in einem awk-Skript
Dabei ist zu beachten, dass die geschweiften Klammern für den Anweisungsblock nur dann notwendig sind, wenn mehr als eine Anweisung im Falle einer erfüllten Bedingung ausgeführt werden soll. Soll beispielsweise nur eine print-Anweisung ausgeführt werden, wäre der folgende Code völlig korrekt:
if(1) print $3
Listing 4.54 print
Aufbau einer Bedingung
Um nun eine if-Anweisung in das Skript einzubauen, müssen Sie zunächst erst einmal wissen, wie sich eine Bedingung eigentlich aufbaut. Dabei wird zwischen wahr (Wert=1) und falsch (Wert=0) unterschieden. Ist eine Bedingung erfüllt (also wahr), so wird/werden die Anweisung(en) ausgeführt, die auf die bedingte Anweisung folgen.
wahr=1; falsch=0; if(wahr) print "Dieser Text wird ausgegeben." if(falsch) print "Dieser Text wird nicht ausgegeben."
Listing 4.55 wahr und falsch
Vergleichs- operatoren
Damit eine Bedingung jedoch sinnvoll zum Einsatz kommen kann, muss die Möglichkeit bestehen, auch Variablen-Werte zu überprüfen.
Dies kann mit den Operatoren Größer-Gleich (>=), Kleiner-Gleich ( <=), Größer (>), Kleiner ( <), Gleich (==) und Ungleich (!=) bewerkstelligt werden.
wahr=1; falsch=0; if(falsch==0) print "Diese Bedingung ist erfüllt!" if(falsch<wahr) print "Diese Bedingung ist ebenfalls erfüllt!" if(falsch>=wahr) print "Diese Bedingung ist NICHT erfüllt!" if(wahr!=0) print "Aber diese ist erfüllt!"
Listing 4.56 Vergleichsoperatoren
!
Das Ausrufezeichen dient zur Negierung einer Bedingung. Möchten Sie beispielsweise erreichen, dass die Bedingung a==1 genau nicht erfüllt ist, kann diese auch durch
if(!a==1)
Listing 4.57 !a==1
ersetzt werden. Diese Methode eignet sich hervorragend, um zu prüfen, ob ein Wert »falsch« ist:
if(!a) { ... }
Listing 4.58 !a
|| und &&
Nehmen wir einmal an, es sollen 100 Anweisungen im Falle einer erfüllten Bedingung ausgeführt werden – und diese 100 Anweisungen sollen auch in dem Fall ausgeführt werden, falls eine andere Bedingung erfüllt ist. Dann wäre es doch sinnvoll, diese Anweisungen nur ein einziges Mal in einen Anweisungsblock einzubauen. Dies ist in awk sehr einfach möglich. Man kann mehrere Bedingungen an eine bedingte Anweisung wie if übergeben. Diese kann man dann durch ein UND (&&) oder ein ODER (||) verknüpfen. Bei einer UND-Verknüpfung werden die Anweisungen nur ausgeführt, wenn alle damit verknüpften Anweisungen »wahr« sind. Bei einer ODER-Verknüpfung muss nur eine der miteinander verknüpften Bedingungen erfüllt werden, um die Ausführung des Anweisungsblocks zu veranlassen.
$ cat /tmp/myfile root 0 /root swendzel 1000 /home/swendzel $ awk '{ # ODER: Nur eine Bedingung MUSS erfüllt seien. # Eine ODER-Bedingung ist auch erfüllt, wenn # BEIDE Teilbedingungen erfüllt sind. if(0 || 1) print $0 \' /tmp/myfile} root 0 /root swendzel 1000 /home/swendzel $ awk '{ # Hier ist die erste Bedingung "falsch", weshalb # die Gesamtbedingung nicht erfüllt ist, da bei # einer UND-Verknüpfung alle Teilbedingungen er- # füllt sein müssen. if(0 && 1) print $0 \' /tmp/myfile} $
Listing 4.59 && und ||
Klammern
In einer Bedingung lassen sich im Übrigen auch Hierarchien einbauen und Teilbedingungen separieren. Dies wird durch Einklammerung realisiert. Im folgenden Beispiel ist die Bedingung nur erfüllt, wenn die erste Bedingung (1) wahr ist und entweder wahr den Wert 1 oder falsch den Wert »1« oder »2« hat:
if( 1 && ( wahr==1 || (falsch==1 || falsch==2) ) ) print $0
Listing 4.60 Klammerung in Bedingungen
else
Eine weitere einfache, aber wiederum äußerst nützliche Fähigkeit von awk (und so ziemlich jeder anderen Programmiersprache) ist das Ausführen von Anweisungen, die nur dann ausgeführt werden, wenn eine Bedingung nicht erfüllt ist. Dazu verwendet man das Schlüsselwort else in Verbindung mit einer if-Anweisung.
if(wahr==321) { print $2 $1 } else { print "Fehler: wahr hat nicht den Wert 321!" }
Listing 4.61 if-else
4.4.8 Schleifen
Um es nicht unnötig kompliziert zu machen: Eine Schleife ist nichts weiter als eine bedingte Anweisung, bei der angegeben wird, wie oft der zugehörige Anweisungsblock ausgeführt werden soll. Die einfachste Form einer Schleife ist die while-Schleife. Mit dieser Schleife werden wir uns auch als Erstes beschäftigen.
while
Die while-Schleife hat äußerlich den gleichen Aufbau wie eine if-Anweisung. Ihr Anweisungsblock (oder eine Einzelanweisung) wird so oft ausgeführt, wie die gegebene Bedingung erfüllt ist.
while ( Bedingung ) { Anweisung1; Anweisung2; }
Listing 4.62 while-Schleife
In der Regel verwendet man Schleifen in Verbindung mit einer Variable. Sollen beispielsweise alle Zahlen von 1 bis 10.000 ausgegeben werden, so werden Sie kaum alle Zahlen selbst in den Code schreiben oder einzeln einer Variable zuweisen. Mit einer Schleife lässt sich dies mit wenigen Zeilen Skriptcode realisieren. Dazu verwenden wir einfach irgendeine Variable, die wir so lange hochzählen, bis ein Maximalwert erreicht ist.
$ awk 'BEGIN { Kundennummer=1; while(Kundennummer <= 10000) { print "Kunde: " Kundennummer Kundennummer++ } \'} Kunde: 1 Kunde: 2 Kunde: 3 ...
Listing 4.63 Beispiel
Dieser Code bietet uns nun eine hervorragende neue Möglichkeit: Egal, wie oft wir die Ausführung einer Anweisung oder eines Anweisungsblocks hintereinander stattfinden lassen wollen, wir müssen sie trotzdem nur ein einziges Mal implementieren. Wenn der obige Code nun nicht 10.000-mal, sondern 9491849-mal oder 0-mal ausgeführt werden soll, müssen wir nur die Zahl 10000 durch eine andere ersetzen, und awk erledigt den Rest.
Schachtelung von Schleifen
Es ist möglich, mehrere Schleifen ineinanderzuschachteln. Dabei ist nichts weiter zu beachten, außer dass man den Code möglichst übersichtlich schreiben sollte.
Zur Vertiefung des bisher Gelernten soll nun ein Beispiel folgen: Es sollen alle Zahlen ausgegeben werden, die größer als 1 und kleiner als 30 sind und durch 3 teilbar sind.
Um diese Aufgabe zu lösen, bauen wir zunächst eine while-Schleife, in der alle Zahlen von 1 bis 29 durchgezählt werden. Für das Durchzählen inkrementieren wir bei jedem Schleifendurchlauf den Wert der Variable Zahl. Um zu prüfen, ob eine Zahl durch 3 teilbar ist, verwenden wir den bereits bekannten Modulo-Operator. Wenn diese Modulo-Operation den Wert 0 zurückgibt, gab es bei der Divison keinen Rest, Zahl ist also durch 3 teilbar. Ist dies der Fall, geben wir mit print den Wert der jeweiligen Zahl aus.
$ awk 'BEGIN { Zahl=1; while(Zahl<30) { if(Zahl%3==0) print Zahl Zahl++ } \'} 3 6 9 12 15 18 21 24 27
Listing 4.64 Verschachtelung von Schleifen
Endlosschleifen
Eine Endlosschleife ist eine niemals endende Schleife. Diese macht oftmals nur bei größeren Softwareprojekten Sinn, etwa bei einem Hintergrundprozess. In awk sind Endlosschleifen eher selten anzutreffen. Bei solch einer Schleife wird einfach eine immer erfüllte Bedingung übergeben, also etwa »1« oder »27!=31«.
while(1) print "Dieser Text wird unendlich oft ausgegeben."
Listing 4.65 Endlosschleife
break und continue
Um die Verwendung von Schleifen zu vereinfachen, kann man das Verhalten des Skripts bezüglich der Schleife innerhalb des Anweisungsblocks der Schleife beeinflussen. Dies mag sich kompliziert anhören, ist es aber nicht. Es gibt nämlich nur zwei Möglichkeiten, die Abarbeitung der Schleife zu beeinflussen:
- break
- break bricht die Schleife ab. Daraufhin werden die nächsten Anweisungen hinter der Schleife behandelt. Um die obige Endlosschleife beispielsweise nur einmal zu durchlaufen, könnte man hinter die print-Anweisung eine break-Anweisung setzen:
while(1) { print "Dieser Text wird unendlich oft ausgegeben." break }Listing 4.66 break
- continue
- continue hingegen bricht nur die aktuelle Abarbeitung des Anweisungsblocks einer Schleife ab. Um die obige Endlosschleife beispielsweise so umzuprogrammieren, dass sie niemals die print-Anweisung aufruft, sondern schlicht nichts tut, außer vor sich hin zu laufen, müsste man nur eine continue-Anweisung vor die print-Anweisung setzen.
while(1) { continue print "Dieser Text wird unendlich oft ausgegeben." }Listing 4.67 continue
do-while
Eine besondere Form der Schleife ist die do-while-Schleife. Dies ist eine while-Schleife, deren Anweisungen mindestens einmal ausgeführt werden. Die erste Ausführung des Anweisungsblocks ist also unbedingt, für alle weiteren muss die Bedingung jedoch erfüllt sein.
do { Anweisung1; Anweisung2; ... } while ( Bedingung )
Listing 4.68 do-while
Würden wir das obige Beispiel also in eine do-while-Schleife übertragen, würde dies folgendermaßen aussehen:
$ awk 'BEGIN { Zahl=1; do { if(Zahl%3==0) print Zahl Zahl++ \ while(Zahl<30)} \'} 3 6 9 12 15 18 21 24 27
for-Schleife
Gegenüber der (do-)while-Schleife hat die for-Schleife einen Vorteil: Ihr kann die Variableninitialisierung und die Anweisung zur Veränderung einer Variable direkt übergeben werden. Das bedeutet, dass die Zuweisung eines Wertes an eine Variable (Initialisierung) und beispielsweise die Dekrementierung einer Variable bei jedem Schleifendurchlauf nicht extra vor bzw. in den Anweisungsblock geschrieben werden müssen.
for ( Initialisierung; Bedingung; Anweisung ) { Anweisung1; Anweisung2; ... }
Listing 4.69 for-Schleife
Nehmen wir einmal das obige Beispiel zur Ausgabe aller durch 3 teilbaren Zahlen zwischen 1 und 29 und bauen es in eine for-Schleife ein:
for(Zahl=1; Zahl<30; Zahl++) if(Zahl%3==0) print Zahl
Listing 4.70 Übersichtlicherer Code dank for
Wie zu sehen ist, konnte das Programm übersichtlich in 3 Zeilen untergebracht werden. <Man könnte es auch in eine einzige Zeile schreiben, dies würde jedoch die Lesbarkeit beeinträchtigen.>
Im Abschnitt zum Thema awk-Arrays wurde bereits der in-Operator in Verbindung mit einer Schleife besprochen, mit dem die einzelnen Array-Elemente durchlaufen werden können. Daher soll an dieser Stelle lediglich auf ihn verwiesen werden.
4.4.9 Funktionen in awk
Ein wichtiges Feature einer Programmiersprache sind die sogenannten Funktionen. Wir werden Funktionen nicht nur in awk, sondern auch in der Shellskriptprogrammierung verwenden. Eine Funktion enthält null, eine oder mehrere Anweisungen und führt diese jedes Mal aus, wenn diese Funktion aufgerufen wird. Dabei können der Funktion immer wieder ein oder mehrere Parameter übergeben werden, mit denen die Funktion dann arbeitet.
Dabei unterscheidet man in awk zwischen den Funktionen, die man selbst in den Skriptcode implementiert, und den sogenannten Builtin-Funktionen. Eine Builtin-Funktion kennen Sie sogar bereits: print. Die print-Funktion gibt Text aus, wobei ihr der Text bzw. die Variablennamen übergeben werden müssen. Diese übergebenen Texte und Variablen sind dabei die im vorherigen Absatz angesprochenen Parameter.
Zunächst werden wir, um Funktionen wirklich zu verstehen, eigene Funktionen erstellen. Anschließend werden die wichtigsten Builtin-Funktionen erklärt. <Eine Liste aller von Ihrem awk-Interpreter unterstützten Funktionen finden Sie in der zugehörigen Manpage.>
Eigene Funktionen implementieren
Eine eigene Funktion muss, bevor sie angewandt werden kann, zunächst implementiert werden. Dazu wird das Schlüsselwort function verwendet. Hinter diesem Schlüsselwort folgt der Name der Funktion und die in Klammern eingeschlossene Parameterliste, wobei diese auch leer sein kann.
function Funktionsname ( ParameterA, ... ParameterN ) { AnweisungA AnweisungB ... AnweisungN }
Listing 4.71 Rohform einer Funktion
Soll beispielsweise eine Funktion implementiert werden, die den Mittelwert von 3 Zahlen berechnet und anschließend ausgibt, könnte dies folgendermaßen aussehen:
$ awk ' function mittel(a, b, c) { mittelwert=(a+b+c)/3 print mittelwert } BEGIN { mittel(1, 3, 3) mittel(395, 3918, 49019849) \'} 2.33333 1.63414e+07
Wie Sie sehen, haben wir die Funktion nicht in einen BEGIN-, Haupt- oder END- Block implementiert. Eine Funktion ist in allen Anweisungsblöcken verfügbar.
return
Jedoch können awk-Funktionen noch etwas mehr: Sie können, wie man es aus der Programmiersprache C kennt, Werte zurückgeben. Diese Wertrückgabe wird durch das Schlüsselwort return bewerkstelligt. Diesen Wert kann man dann einer Variable zuweisen oder auch an eine andere Funktion als Parameter übergeben. Zudem kann man den Wert auch in eine Bedingung einbauen.
Nehmen wir das vorherige Beispiel noch einmal, und verwenden wir nun anstelle der print-Funktion innerhalb der Funktion eine return- Anweisung. Dies ermöglicht es uns, die Funktion viel dynamischer einzusetzen. Dieses Beispiel verwendet den Rückgabewert der Funktion für eine bedingte Anweisung und übergibt den Wert einer print-Funktion.
$ awk ' function mittel2(a, b, c) { return (a+b+c)/3; } BEGIN { w1=55 w2=54 w3=53 while(mittel2(w1, w2, w3)>50) { print mittel2(w1, w2, w3); w1--; w2-=2; w3+=0.5; } \'} 54 53.1667 52.3333 51.5 50.6667
Listing 4.72 return
Builtin-Funktionen
Neben den Funktionen, die Sie selbst implementieren können, stellt awk Ihnen einige vorgegebene Builtin-Funktionen zur Verfügung. Diese gliedern sich in drei Bereiche: in die mathematischen Funktionen, in die Stringfunktionen und in die sonstigen Funktionen. Informationen zu Letzteren finden Sie in der Manpage Ihres awk-Interpreters.
Mathematische Funktionen
awk stellt die in Tabelle 4.2 dargestellten mathematischen Builtin-Funktionen zur Verfügung.
Funktion | Erklärung |
atan2(y, x) | Gibt den Arcustangens von x zurück. |
cos(x) | Gibt den Kosinus-Wert von x zurück. |
exp(x) | Gibt den Wert von e^x zurück. |
int(x) | Gibt den Ganzzahlwert (Integerwert) von x zurück. Wäre x etwa 17.341, würde int(x) den Wert 17 zurückgeben. |
log(x) | Gibt den natürlichen Logarithmus von x zurück. |
rand() | Gibt eine zufällige Zahl zwischen 0...1 zurück. Mit der Funktion srand(x) kann ein neuer Startwert für rand() gesetzt werden. |
sin(x) | Gibt den Sinus von x zurück. |
sqrt(x) | Gibt die Wurzel von x zurück. |
Stringfunktionen
Kommen wir nun zu den wohl wichtigsten Funktionen in awk: den Stringfunktionen. In awk stehen Ihnen dabei folgende Funktionstypen zur Verfügung: Funktionen, die
- Strings in Strings suchen
- reguläre Ausdrücke suchen und ersetzen
- die Stringlänge zurückgeben
- Strings aufspalten
- Text (formatiert) ausgeben
- Kleinbuchstaben eines Strings in Großbuchstaben umwandeln
- Großbuchstaben eines Strings in Kleinbuchstaben umwandeln
Eine Liste aller Stringfunktionen samt einer Beschreibung dieser Funktionen finden Sie in der Manpage zu awk bzw. nawk oder gawk.
4.4.10 Ein paar Worte zum Schluss
Dies war eine kleine Einführung in awk. Doch awk kann noch mehr. Es gibt Funktionalitäten, die wir nicht beschrieben haben (etwa Schlüsselwörter wie next oder exit oder Bedingungen in regulären Ausdrücken beim awk-Aufruf). Doch sollte in diesem Rahmen das Wichtigste, was man über awk wissen sollte, um es täglich zu verwenden, vermittelt worden sein. Alles Weitere finden Sie in der jeweiligen Manpage Ihres Interpreters.