Eingabe zeilenweise verarbeiten
Die eigentliche Stärke von AWK: Muster, die auf jede Zeile angewendet werden. Im Kurs erzeugen wir die Daten direkt im Beispiel (per printf und Pipe), wie man es auch in einem Shell-Skript tun würde.
printf 'Mia 17 Berlin\nTom 25 Hamburg\nZoe 31 Koeln\nBen 12 Berlin\n' | awk '
NR == 1 { print "Erste Zeile:", $0 }
$2 > 20 { print $1, "ist über 20" }
/Berlin/ { berlin++ }
END { print NR, "Zeilen,", berlin, "aus Berlin" }
'Erste Zeile: Mia 17 Berlin Tom ist über 20 Zoe ist über 20 4 Zeilen, 2 aus Berlin
Mehrere Muster pro Programm sind erlaubt; trifft eine Zeile mehrere, laufen alle Aktionen nacheinander.
Spalten, Trenner und Formatierung
printf 'name;preis;menge\nApfel;1.20;10\nBirne;0.80;25\nKiwi;2.50;4\n' | awk -F';' '
BEGIN { OFS = " | " }
NR == 1 { print $1, $2, $3, "summe"; next }
{
summe = $2 * $3
gesamt += summe
printf "%-6s %6.2f %4d %8.2f\n", $1, $2, $3, summe
}
END { printf "Gesamt: %.2f\n", gesamt }
'name | preis | menge | summe Apfel 1.20 10 12.00 Birne 0.80 25 20.00 Kiwi 2.50 4 10.00 Gesamt: 42.00
next springt zur nächsten Zeile. Mit -F legst du den Feldtrenner fest, auch als Regex (-F'[,;]').
Muster-Bereiche und Bedingungen
printf 'a\nSTART\nb\nc\nEND\nd\n' | awk '/START/,/END/ { print NR ": " $0 }'
echo ---
printf '1\n2\n3\n4\n5\n6\n' | awk 'NR % 2 == 0'
echo ---
printf 'x 5\ny 15\nz 25\n' | awk '$2 >= 10 && $2 < 20'
echo ---
printf 'a b c\n\nd e\n' | awk 'NF { print NF ": " $0 }'
echo ---
printf 'eins\nzwei\ndrei\n' | awk 'END { print $0, NR }'2: START 3: b 4: c 5: END --- 2 4 6 --- y 15 --- 3: a b c 2: d e --- drei 3
Mehrere Dateien und FILENAME
printf 'a\nb\n' > /tmp/awk-eins.txt
printf 'c\nd\ne\n' > /tmp/awk-zwei.txt
awk '{ print FILENAME ":" FNR ":" NR ": " $0 }' /tmp/awk-eins.txt /tmp/awk-zwei.txt
awk 'FNR == 1 { print "== " FILENAME " ==" } END { print NR " Zeilen insgesamt" }' /tmp/awk-eins.txt /tmp/awk-zwei.txt
rm /tmp/awk-eins.txt /tmp/awk-zwei.txt/tmp/awk-eins.txt:1:1: a /tmp/awk-eins.txt:2:2: b /tmp/awk-zwei.txt:1:3: c /tmp/awk-zwei.txt:2:4: d /tmp/awk-zwei.txt:3:5: e == /tmp/awk-eins.txt == == /tmp/awk-zwei.txt == 5 Zeilen insgesamt
Ausgabe umleiten und Pipes
printf 'b 2\na 1\nc 3\n' | awk '{ print $1, $2 | "sort" } END { close("sort"); print "fertig" }'
printf '1\n2\n3\n' | awk '{ s += $1 } END { print "Summe:", s, "Mittel:", s / NR }'
printf 'x\n' | awk '{ print "auf stderr" > "/dev/stderr"; print "auf stdout" }' 2>/dev/null
printf 'ein Satz hier\n' | awk '{ for (i = NF; i >= 1; i--) printf "%s%s", $i, (i > 1 ? " " : "\n") }'a 1 b 2 c 3 fertig Summe: 6 Mittel: 2 auf stdout hier Satz ein
Merke
- Muster wählen Zeilen aus (Regex, Vergleich, Bereich
a,b), Aktionen verarbeiten sie -Fsetzt den Feldtrenner,OFSden Ausgabe-Trenner;nextüberspringt eine ZeileNRzählt über alle Dateien,FNRpro Datei;FILENAMEnennt die Datei- Ausgabe lässt sich mit
>und|umleiten (close()nicht vergessen)
Aufgabe
Summiere die dritte Spalte einer CSV-Datei, gruppiert nach der ersten Spalte.