Grundbausteine
AWK nutzt erweiterte reguläre Ausdrücke (ERE). Sie stehen zwischen /.../, als Zeichenkette oder in einer Variablen:
BEGIN {
t = "Datum: 2024-03-15, Mail: mia@example.com, Tel: +49 30 12345"
print (t ~ /[0-9]{4}-[0-9]{2}-[0-9]{2}/)
print (t ~ /^Datum/), (t ~ /Tel$/), (t ~ /Tel: \+49/)
muster = "[a-z]+@[a-z]+\\.com"
print (t ~ muster)
print match(t, /[a-z]+@[a-z]+\.[a-z]+/), RSTART, RLENGTH
print substr(t, RSTART, RLENGTH)
n = gsub(/[0-9]/, "#", t)
print n, t
}1 1 0 1 1 26 26 15 mia@example.com 17 Datum: ####-##-##, Mail: mia@example.com, Tel: +## ## #####
| Baustein | Bedeutung |
|---|---|
. | beliebiges Zeichen |
* + ? | beliebig oft / mindestens einmal / optional |
{n,m} | n bis m Wiederholungen |
[abc] [^abc] [a-z] | Zeichenklassen |
(a|b) | Alternative |
^ $ | Anfang/Ende |
[[:alpha:]] [[:digit:]] [[:space:]] | POSIX-Klassen |
\\. | maskierter Punkt (in Strings doppelt maskieren) |
Mit Treffern arbeiten
Mit gawks match(string, regex, array) erhältst du Teiltreffer in Gruppen:
BEGIN {
zeile = "192.168.0.15 - - [15/Mar/2024:14:30:00] \"GET /index.html HTTP/1.1\" 200 5120"
if (match(zeile, /^([0-9.]+) .*\[([^\]]+)\] "([A-Z]+) ([^ ]+) [^"]*" ([0-9]+) ([0-9]+)/, g)) {
print "IP: ", g[1]
print "Zeit: ", g[2]
print "Methode: ", g[3]
print "Pfad: ", g[4]
print "Status: ", g[5]
print "Bytes: ", g[6]
}
print gensub(/([0-9]+)\/([A-Za-z]+)\/([0-9]+)/, "\\3-\\2-\\1", "g", "15/Mar/2024")
s = "Hallo Welt"
print gensub(/(\w+) (\w+)/, "\\2 \\1", 1, s)
print gensub(/o/, "0", "g", s)
print gensub(/o/, "0", 2, s)
}IP: 192.168.0.15 Zeit: 15/Mar/2024:14:30:00 Methode: GET Pfad: /index.html Status: 200 Bytes: 5120 2024-Mar-15 Welt Hallo Hall0 Welt Hallo Welt
Felder und Trenner als Regex
printf 'a1b22c333d\n' | awk -F'[0-9]+' '{ for (i = 1; i <= NF; i++) printf "[%s]", $i; print "" }'
printf 'a, b;c ,d\n' | awk -F' *[,;] *' '{ print NF; print $1 "|" $2 "|" $3 "|" $4 }'
printf 'ein Wort\tund mehr\n' | awk '{ print NF ": " $1 "-" $2 "-" $3 "-" $4 }'
printf 'key=value\n' | awk -F= '{ print $2 "=" $1 }'
printf 'x y z\n' | awk '{ $2 = "NEU"; print; print NF }'
printf 'x y z\n' | awk '{ $5 = "e"; print; print NF }'
printf 'a:b:c\n' | awk 'BEGIN { FS = ":"; OFS = "-" } { $1 = $1; print }'[a][b][c][d] 4 a|b|c|d 4: ein-Wort-und-mehr value=key x NEU z 3 x y z e 5 a-b-c
Weist du einem Feld etwas zu, baut AWK $0 mit OFS neu zusammen ($1 = $1 erzwingt das).
Typische Muster
function trim(s) { gsub(/^[ \t]+|[ \t]+$/, "", s); return s }
function ist_zahl(s) { return s ~ /^[-+]?[0-9]+(\.[0-9]+)?$/ }
function ist_email(s) { return s ~ /^[[:alnum:]._-]+@[[:alnum:].-]+\.[a-z]{2,}$/ }
function ist_ipv4(s, p, i, n) {
n = split(s, p, ".")
if (n != 4) return 0
for (i = 1; i <= 4; i++) if (p[i] !~ /^[0-9]+$/ || p[i] > 255) return 0
return 1
}
BEGIN {
print "[" trim(" mitte ") "]"
print ist_zahl("-12.5"), ist_zahl("12a"), ist_zahl("7")
print ist_email("mia@example.com"), ist_email("kaputt@"), ist_email("a.b-c@x-y.org")
print ist_ipv4("192.168.0.1"), ist_ipv4("256.1.1.1"), ist_ipv4("1.2.3")
text = "Die Katze jagt die Maus. Die Maus flieht."
anzahl = gsub(/[Dd]ie/, "&!", text)
print anzahl, text
}[mitte] 1 0 1 1 0 1 1 0 0 3 Die! Katze jagt die! Maus. Die! Maus flieht.
& steht in der Ersetzung für den gesamten Treffer.
Merke
- AWK nutzt ERE:
{n,m},(a|b),[[:alpha:]]; Backslashes in Strings doppelt schreiben - gawk:
match(s, re, arr)liefert Gruppen,gensubersetzt mit Rückbezügen (\\1) - Der Feldtrenner
-Fdarf ein Regex sein &insub/gsubsteht für den ganzen Treffer
Aufgabe
Zerlege eine Apache-Logzeile mit match in IP, Zeit und Statuscode.