Gawk/Array
Arrays
- Ein Array ist eine Variable, die einen Satz von Daten - Elemente genannt - aufnehmen kann.
- Der Elementzugriff erfolgt über einen Index, der eine Nummer oder eine Zeichenkette sein kann, wobei - im Falle von Zeichenketten - die Groß- und Kleinschreibung stets keine Rolle spielt, unabhängig vom Wert der internen Variablen IGNORECASE! Der Name eines Arrays darf nicht mit dem Namen einer »einfachen« Variablen kollidieren.
- Die Größe eines Arrays muss nicht vorab angegeben werden.
- Jederzeit lassen sich weitere Elemente zum Array hinzufügen, löschen oder der Wert eines Elements verändern.
Einfügen / Löschen von Elementen
- Mit jeder Zuweisung eines Wertes an einen neuen Index wächst das Array um ein weiteres Element.
Im Falle eines existierenden Indizes wird der alte Wert durch den neuen ersetzt:
Array [Index] = Wert
- Neben eindimensionalen Arrays gestattet Awk auch die Verwendung mehrdimensionaler Felder.
- Im zweidimensionalen Fall sind zwei Indizes zur Adressierung eines Elements notwendig:
- ZweiDimensionalesArray [Index1, Index2] = Wert
- Intern bildet Awk mehrdimensionale Felder auf ein eindimensionales ab, indem die einzelnen Indizes implizit zu einer einzelnen Zeichenkette verkettet werden.
- Um die Indizes identifizieren zu können, wird der durch SUBSEP definierte Separator als Trennzeichen zwischen diese gesetzt.
- In der Voreinstellung von SUBSEP wird bspw. aus »f[1,2]« intern ein »f["1@2"]«.
- Beide Angaben sind äquivalent.
- Zum Entfernen eines Elements dient der delete -Operator.
Erforderlich ist die Angabe des Indexes des zu löschenden Elements:
delete array [Index]
- Wird delete einzig der Name eines Array übergeben - also ohne einen Index - werden sämtliche Elemente des Feldes gelöscht.
Index-Zugriff
- Der Zugriff auf ein Element eines Feldes ist stets über seinen Index möglich.
- Dies setzt voraus, dass der Index bekannt ist.
Erfolgt eines Referenzierung mittels eines unbekannten Indizes, wird eine leere Zeichenkette als Ergebnis geliefert und gleichzeitig diese als Element des Arrays angelegt:
$ awk 'BEGIN { f[A]="foo"; > printf("_%s_%s_\n", f[A], f[B]);}' _foo_foo_
- Eventuell haben Sie mit dem Verständnis des Beispiels so Ihre Probleme? Kein Wunder, es wurde bewusst ein Fehler eingebaut.
- Und zwar werden A und B als Namen von Variablen betrachtet und beide zur leeren Zeichenkette evaluiert.
- Hieraus resultiert, dass jeweils auf »f[""]« - also auf einundenselben Feldindex - zugegriffen wird.
Die korrigierte Variante bringt das vorhergesagte Ergebnis:
$ awk 'BEGIN { f["A"]="foo"; > printf("_%s_%s_\n", f["A"], f["B"]);}' _foo__
- Das automatische Anlegen eines neuen Indizes im Falle dessen Nichtexistenz ist vermutlich in etlichen Fällen unerwünscht.
Aus diesem Grund bietet Awk eine Abfrage an, um festzustellen, ob ein Index existiert:
if ( Index in Array ) { # tue etwas }
Ein komplexeres Beispiel zum Indexzugriff druckt die Felder der Datei /etc/passwd in tabellarischer Form, wobei die notwendige Spaltenbreite berechnet wird:
#!/usr/bin/awk -f BEGIN { FS=":"; while ( getline < "/etc/passwd" ) for (i=1; i<=6; i++) if (max[i] < length($i)) { max[i] = length($i)} close("/etc/passwd" ) while ( getline < "/etc/passwd" ) printf("%-*s %*s %*s %-*s %-*s\n", max[1], $1, max[3], $3, max[4], $4, max[5], $5, max[6], $6); }
Scannen eines Arrays
- Unter »Scannen eines Arrays« wollen wir den sequentiellen Zugriff auf alle enthaltenen Elemente in der Reihenfolge ihres Einfügens verstehen.
- Im Falle eindimensionaler Felder wird in Awk einfach in einer for -Schleife eine Variable der Reihe nach mit jedem Index aus dem Array verbunden.
Im Schleifenrumpf kann nachfolgend auf das mit dem Index verbundene Elemente zugegriffen werden.
for ( Index in Array ) { # tue etwas (mit Array[Index]) }
Das nachfolgende Beispiel demonstriert die Anwendung des Scannens, indem eine Liste der Häufigkeiten des Auftretens von Wörtern aus der Eingabe generiert wird:
#!/usr/bin/awk -f BEGIN { RS="space:" } { ++wort[$0] } END { for (x in wort) printf("%-20s %d\n", x, wort[x]); }
Ein simpler Test beweist, dass das Skript (»WorkCounter.awk« genannt) tatsächlich funktioniert:
$ echo drei eins drei zwei zwei drei | WordCounter.awk zwei 2 drei 3 eins 1
- Der Zugriff auf die Elemente in einem mehrdimensionalen Feld kann analog erfolgen, wenn der Elementzugriff über den verketteten Index genügt.
Werden hingegen die originalen Indizes benötigt, ist etwas mehr Aufwand zu betreiben:
for ( VollerIndex in Array ) { split ( VollerIndex, Hilfsfeld, SUBSEP ) # Index1 steht in Hilfsfeld[1], # Index2 steht in Hilfsfeld[2]) usw. } }
- Die Zeichenkettenfunktion split soll im folgenden Abschnitt behandelt werden.
- Sie trennt den Inhalt von VollerIndex an den durch SUBSEP vorgegebenen Positionen auf und speichert die einzelnen Bestandteile in Hilfsfeld.
Ein sinnfreies Beispiel veranschaulicht die Methodik der Index-Aufsplittung:
$ awk 'BEGIN { > f[1,"foo",0815] = "egal"; > for (i in f) { > split (i,hf,SUBSEP); > for (x in hf) print hf[x] > } } 1 foo 815