ubuntuusers.de

ubuntuusers.deWikiawk

awk

Zum Verständnis dieses Artikels sind folgende Seiten hilfreich:

Wiki/Icons/terminal.png awk ist eine Skriptsprache zum Editieren und Analysieren von Texten. Eingabedaten werden dabei immer zeilenweise abgearbeitet. Der Name awk leitet sich von den Anfangsbuchstaben der Entwickler Alfred V. Aho, Peter J. Weinberger und Brian W. Kernighan ab.

Ein Werkzeug mit ähnlichen Aufgabengebieten findet man bei sed, während die Programmiersprache Perl durch ihre unzählige Zusatzmodule praktisch unbegrenzt erweitert werden kann.

Installation

Der Interpreter ist in der Standardinstallation von Ubuntu bereits enthalten, kann ansonsten aber über das folgende Paket installiert [1] werden:

  • mawk

Wiki/Vorlagen/Installbutton/button.png mit apturl

Paketliste zum Kopieren:

sudo apt-get install mawk 

sudo aptitude install mawk 

Darüber hinaus existieren noch die Pakete gawk (englische Dokumentation im info-Format in gawk-doc) und original-awk.

Erste Schritte

awk-Programme bestehen immer aus Kombinationen von Anweisungsblöcken und zugehörigen Bedingungen, welche für die aktuelle Eingabezeile erfüllt sein müssen, damit der Anweisungsblock ausgeführt wird. Wird keine Bedingung angegeben, wird die Anweisung für jede Eingabezeile ausgeführt. Wird nur die Bedingung, jedoch keine Anweisung angegeben, so wird die Standardanweisung ausgeführt, welche die Eingabezeile ausgibt. Anweisungsblöcke werden immer in geschweiften Klammern zusammengefasst.

Allgemeine Syntax mit Bedingung und Anweisung:

Bedingung { Anweisungen }

Bedingungen

Eine übliche Bedingung ist der Vergleich mit einem regulären Ausdruck:. Dies wird wie folgt geschrieben:

/regulärer Ausdruck/              # Kurzform für Vergleich mit der aktuellen Zeile
$0 ~ /regulärer Ausdruck/         # Langform
/^Hallo /                         # Beispiel: alle Zeilen, die mit "Hallo " beginnen
/[0-9]+\.[0-9]+/                  # komplexeres Beispiel: alle Zeilen, die eine Dezimalzahl mit "." als Trennzeichen enthalten (z.B. 3.45)

Man kann auch andere Vergleiche durchführen. Statt ~ für "entspricht" lässt sich dabei auch immer !~ für "entspricht nicht" nutzen.

Ausdruck ~ /regulärer Ausdruck/   # allgemein
$1 ~ /^Hallo$/                    # Beispiel: vergleicht das erste Feld der Zeile (siehe "Variablen"); (fast) identisch zum 1. Beispiel oben

Schließlich kann man auch Vergleiche ohne reguläre Ausdrücke durchführen:

Ausdruck Operator Ausdruck        # allgemein
$1 == "Hallo"                     # Beispiel: wie "$1 ~ /^Hallo$/"
$1 > 20                           # Beispiel: prüft, ob der Wert im ersten Feld größer als 20 ist

Mehrere Bedingungen lassen sich auch mit && (und) bzw. || (oder) verknüpfen.

Spezielle Bedingungen

Es gibt die besonderen Bedingungen BEGIN und END. Anweisungen im BEGIN Block werden ausgeführt bevor die erste Zeile der Eingabedaten eingelesen wird. Hier können z.B. eigene Variablen initialisiert werden. Anweisungen im END Block werden nach der letzten Zeile ausgeführt.

Das Beispiel wertet die Datei /etc/hosts aus:

awk '
 BEGIN { print "Die IP Adresse von localhost ist: " }
 $2 == "localhost" { print $1 }
 END   { print "Das war die IP Adresse von localhost."}
 ' /etc/hosts 

Ergebnis:

Die IP Adresse von localhost ist: 
127.0.0.1
Das war die IP Adresse von localhost.

Variablen

awk setzt beim Einlesen jeder Zeile bestimmte Variablen. $0 ist immer die komplette Zeile. Mit $1, $2 usw. kann man auf die einzelnen Felder der Zeile zugreifen. Felder werden in der Voreinstellung durch Leerraum (whitespace) voneinander getrennt. In der Variable NF steht die Anzahl der Felder in der aktuellen Zeile. Somit kann man auf die Felder $1 - $NF zugreifen. Die Variable NR enthält die aktuelle Zeilennummer. Mit jeder neu eingelesenen Zeile wird NR um eins erhöht.

Ausführung auf der Kommandozeile

awk-Skripte können auf der Kommandozeile ausgeführt werden. Eingabedaten werden entweder über den Standardeingabekanal gelesen oder aus einer oder mehreren angegebenen Dateien. Das Skript kann dabei in einfachen Hochkomma direkt hinter dem awk-Aufruf stehen. Wenn man zum Beispiel die IP-Adresse des localhost-Eintrags aus der Datei /etc/hosts auslesen möchte, könnte man das über folgendes Skript tun:

awk '$2 == "localhost" { print $1 }' /etc/hosts 

Ergebnis:

127.0.0.1

awk kann die Eingaben auch vom Standardeingabekanal lesen:

awk '$2 == "localhost" { print $1 }' < /etc/hosts 

Ausführung als Skriptdatei

Längere awk-Skripte werden auf der Kommandozeile schnell unübersichtlich. Daher können Skripte auch als Datei gespeichert werden. Auf der Kommandozeile können diese dann mit

awk -f Datei 

ausgeführt werden. Wenn also das Beispielskript in der Datei localhostip.awk gespeichert wäre, würde der Aufruf so erfolgen:

awk -f localhostip.awk /etc/hosts  

Alternativ kann man den Befehl awk -f auch in die Shebangzeile des Skripts packen:

1
2
#!/bin/awk -f
'$2 == "localhost" { print $1 }'

und dann dem Skript Ausführungsrechte geben:

chmod a+x localhostip.awk  

Der Aufruf erfolgt mit:

./localhostip.awk /etc/hosts  

Variablen

Variablen müssen in awk-Skripten nicht speziell initialisiert werden. Es kann jederzeit einer neuen Variable ein Wert zugewiesen werden.

Builtin-Variablen

awk belegt einige Variablen automatisch mit Werten. Diese können im laufenden Skript abgefragt und verändert werden, wobei Änderungen nicht bei allen Variablen sinnvoll sind. Einige davon zeigt die folgende Tabelle:

Name Bedeutung
ARGC Anzahl der Argumente
ARGV Array mit den übergebenen Argumenten
ENVIRON Array der Umgebungsvariablen
FILENAME Name der Eingabedatei
NF Anzahl der Felder in derzeitigen Zeile
NR Anzahl der Zeilen seit Skriptstart
FNR Anzahl der Zeilen aus der aktuellen Eingabedatei
FS Der aktuelle Feldtrenner. Anhand dieses Trenners werden die Variablen $1 - $NF belegt.
FIELDWIDTHS Eine mit Leerzeichen getrennte Liste von Feldbreiten. Wenn diese Variable gesetzt wird, werden Felder nicht mehr anhand des Feldtrenners FS getrennt, sondern nach festen Breiten. Dies ist vor allem dann sinnvoll, wenn der auszuwertende Text mit festen Breiten formatiert ist.

Variablen übergeben

Oft ist es sinnvoll, dem awk-Skript eigene Variablen zu übergeben, welche dann im Skript verwendet werden können. Mit dem Aufrufparameter -v können solche Variablen gesetzt und im Skript genutzt werden.

awk -v pre="IP von localhost ist:" -v post="Das war die IP von localhost." '
   BEGIN { print pre }
   $2 == "localhost" { print $1 }
   END   { print post}
' /etc/hosts 

Ergebnis:

IP Adresse von localhost ist:
127.0.0.1
Das war die IP von localhost

Programmsteuerung

Auch awk hat einige Funktionen zur Programmsteuerung die wahrscheinlich schon von anderen Programmiersprachen bekannt sind.

Bedingungen

Mit if-else können Bedingungen überprüft werden und der Programmablauf entsprechend gesteuert werden.

if (bedingung) {
    # Anweisungen wenn Bedingung erfüllt
} else {
    # Anweisungen wenn Bedingung nicht erfüllt
}

Das Beispiel überprüft, ob eine Zahl x gerade oder ungerade ist. % steht für "Modulo" (der Rest bei einer Division mit Rest).

1
2
3
4
5
if (x % 2 == 0) {
   print x " ist eine gerade Zahl." 
} else  {
   print x " ist eine ungerade Zahl."
}

Schleifen

Schleifen dienen der Wiederholung von Anweisungen.

while-Schleife

In der while-Schleife wird eine Bedingung überprüft. Wenn die Bedingung wahr ist, wird der Schleifenkörper ausgeführt. Nach dem Schleifenkörper wird die Bedingung erneut überprüft usw. Es muss also sichergestellt werden, dass sich die Bedingung innerhalb der Schleife ändert, damit keine Endlosschleife entsteht.

while (Bedingung) {
   Anweisungen
}

Beispiel (gibt die Zahlen 1-9 aus):

1
2
3
4
5
i=1
while (i<10) {
   print i
   i = i + 1;
}

do-while-Schleife

Die do-while-Schleife ist prinzipiell ähnlich zur while-Schleife, mit dem Unterschied, dass die Bedingung erst _nach_ dem Durchlauf des Schleifenkörpers überprüft wird. Sie wird also immer mindestens einmal durchlaufen.

do {
  Anweisung
} while (Bedingung)

Beispiel (gibt die Zahl 10 einmal aus, obwohl die Bedingung nicht erfüllt ist):

1
2
3
4
i = 10
do {
   print i
} while (i < 10)

for-Schleife

Die for-Schleife ist immer dann hilfreich, wenn eine genau festgelegte Anzahl an Ausführungen des Schleifenkörpers gewünscht wird. Die Schleife besteht aus drei Teilen: Einer Initialisierung, einer Bedingung und einer Inkrement-Anweisung. Der Schleifenkörper wird ausgeführt, wenn die Bedingung erfüllt ist. Die Überprüfung der Bedingung findet bei der for-Schleife wie bei der while-Schleife vor dem Durchlauf des Schleifenkörpers statt.

for(Initialisierung; Bedingung; Inkrement) {
   Anweisung
}

Beispiel (gibt die Zahlen 1-9 aus):

1
2
3
for (i=1; i<10; i++) {
   print i
}

break und continue

Mit den Befehlen break und continue kann der Ablauf innerhalb der Schleife kontrolliert werden. Mit break wird die Schleife sofort verlassen. Mit continue wird die der Schleifenkörper erneut von vorne durchlaufen, wodurch auf das continue folgende Anweisungen übersprungen werden. Bei einer for-Schleife wird dabei auch noch die Inkrement-Anweisung ausgeführt.

next, nextfile und exit

Mit next kann awk angewiesen werden, sofort die nächste Zeile einzulesen und damit weiterzuarbeiten. Mit nextfile wird die Abarbeitung der derzeitigen Datei beendet und mit der nächsten Datei weitergemacht oder das Skript beendet, falls es die letzte Eingabedatei war. Mit exit wird das Skript sofort beendet.

Anweisungen

Hinter einer Anweisung kann ein Semikolon eingefügt werden. Dies ist immer notwendig, wenn mehrere Anweisungen auf einer Zeile stehen.

Hier sollen noch ein paar weitere Anweisungen vorgestellt werden. Mehr findet man in der Manpage von awk unter "8. Built-in functions" und "9. Input and output".

Anweisung Nutzung
gsub(regulärer Ausdruck, Ersetzung, Variable) Ersetzt alle Vorkommen des regulären Ausdrucks in der Variablen. Wird keine Variable angegeben, wird $0 verwendet.
sub(regulärer Ausdruck, Ersetzung, Variable) Wie gsub, aber es wird höchstens eine Ersetzung vorgenommen.
index(Zeichenkette 1, Zeichenkette 2) Sucht Zeichenkette 2 in Zeichenkette 1 und gibt die Position in Zeichenkette 1 oder 0 für "nicht gefunden" zurück.
match(Zeichenkette, regulärer Ausdruck) Wie index, aber es wird nach einem regulären Ausdruck gesucht.
length(Zeichenkette) Gibt die Länge der Zeichenkette zurück.
substr(Zeichenkette, Start, Länge) Gibt den Ausschnitt aus der Zeichenkette zurück, der bei Index "Start" beginnt. Wird eine Länge angegeben, werden nur so viele Zeichen zurückgegeben.

Beispiele

Beispiele für awk-Skripte findet man u.a. in der Manpage von awk unter "EXAMPLES". Ein paar sollen hier noch aufgeführt werden.

Spalten ausgeben

awk wird oft verwendet, um eine bestimmte Spalte (hier: die erste) auszugeben. Eine ähnliche Funktion hat cut.

1
{ print $1 }

Werden die Spalten nicht durch Leerzeichen getrennt, kann man die Variable FS ändern, indem man awk mit folgendem Befehl aufruft:

awk -F Neuer-FS-Wert '{ print $1 }' 

Summe bilden

Dieses Skript erwartet Zeilen, die jeweils genau eine Zahl enthalten, und gibt die Anzahl der Zeilen, die Summe aller Zahlen sowie den Durchschnitt aus:

1
2
3
4
5
6
7
{
    nr += 1
    sum += $0
}
END {
    print "Anzahl:", nr, "Summe:", sum, "Durchschnitt:", sum / nr
}

Intern

Extern

Diese Revision wurde am 31. Oktober 2013 10:44 von blaufotograph erstellt.
Die folgenden Schlagworte wurden dem Artikel zugewiesen: Programmierung, Shell