awk-Befehl: Felder ausgeben, Trennzeichen mit -F und Bedingungsmuster
Der Befehl awk ist ein Linux-Werkzeug, das eine Textdatei Zeile für Zeile liest, jede Zeile an Leerzeichen oder einem von dir angegebenen Trennzeichen in Felder zerlegt und nur die Felder der Zeilen ausgibt oder berechnet, die eine Bedingung erfüllen. Auf einem AlmaLinux-9-Server haben wir aus einer Beispieldatei mit dem Zugriffslog eines Webservers die Anfragen pro Client-IP und die Anzahl pro Statuscode mit einer einzigen, per Pipe mit sort verbundenen Zeile ausgezählt: Alle drei 404-Antworten unter den zwölf Zeilen waren Anfragen an wp-login.php und .env von einer einzigen IP.
Die folgende Ausgabe entstand mit dem root-Konto in einem Arbeitsordner auf einem AlmaLinux-9.8-Server. Zugriffslog, Kontenliste, Verkaufsdaten und Punktedatei sind für den Test erstellte Beispieldateien, und die IP-Adressen und Kontonamen darin sind ebenfalls Beispielwerte.
1️⃣ Grundlegende Verwendung des awk-Befehls
awk zerlegt jede gelesene Zeile an Leerzeichen und nummeriert die Felder von vorne als $1, $2, $3. Geprüft haben wir das mit scores.txt, in der Name, Ergebnis und Punktzahl durch Leerzeichen getrennt sind.
cat scores.txtalice pass 82
bob fail 47
carol pass 91
dave pass 68
erin fail 55Die geschweiften Klammern in den einfachen Anführungszeichen enthalten die Aktion, die für jede Zeile läuft, und wenn du nach print Feldnummern mit Kommas auflistest, werden nur diese Felder ausgegeben. Gibst du das erste und dritte Feld aus, bleiben nur Name und Punktzahl.
awk '{print $1, $3}' scores.txtalice 82
bob 47
carol 91
dave 68
erin 55Lässt du das Komma zwischen den Feldern weg und schreibst $1 $3, laufen die beiden Werte ohne Leerzeichen zusammen. Das Komma in print setzt das Ausgabetrennzeichen (standardmäßig ein Leerzeichen), Werte ohne Komma werden zu einer Zeichenkette verbunden.
awk '{print $1 $3}' scores.txtalice82
bob47
carol91
dave68
erin55NR ist die Nummer der bisher gelesenen Zeile, NF die Anzahl der Felder in dieser Zeile. $NF bezeichnet das letzte Feld, du kannst die letzte Spalte also auch dann wählen, wenn die Feldzahl von Zeile zu Zeile schwankt.
awk '{print NR, NF, $NF}' scores.txt1 3 82
2 3 47
3 3 91
4 3 68
5 3 55Auch das Zugriffslog eines Webservers ist durch Leerzeichen getrennt, die Felder wählst du also auf dieselbe Weise. Die Feldnummern der ersten Zeile des Test-Zugriffslogs sehen so aus.
| Feld | Wert in der ersten Zeile | Bedeutung |
|---|---|---|
| $1 | 192.0.2.10 | Client-IP |
| $4 | [29/Oct/2026:00:01:12 | Datum und Uhrzeit der Anfrage |
| $6 | "GET | Anfragemethode (mit vorangestelltem doppeltem Anführungszeichen) |
| $7 | /index.html | Anfrage-URL |
| $9 | 200 | Statuscode |
| $10 | 5120 | Gesendete Bytes |
| $11 | "-" | Vorherige Seite (Referer) |
| $12~$15 | "Mozilla/5.0 (X11; Linux x86_64)" | User-Agent (an jedem Leerzeichen getrennt) |
Wir haben $1, $7 und $9 ausgegeben, also Client-IP, Anfrage-URL und Statuscode.
awk '{print $1, $7, $9}' access.log192.0.2.10 /index.html 200
198.51.100.7 /about.html 200
192.0.2.10 /images/logo.png 200
203.0.113.25 /wp-login.php 404
203.0.113.25 /wp-login.php 404
192.0.2.10 /contact.html 200
198.51.100.7 /old-page.html 301
203.0.113.25 /.env 404
192.0.2.44 /index.html 200
198.51.100.7 /api/search?q=awk 500
192.0.2.44 /images/logo.png 304
192.0.2.10 /index.html 200Eine Spalte mit Leerzeichen im Wert, etwa der User-Agent, wird in mehrere Felder zerlegt. NF war in allen ersten drei Zeilen 15, und $NF ist das letzte Stück des User-Agents.
awk '{print NF, $NF}' access.log | head -315 x86_64)"
15 x86_64)"
15 x86_64)"2️⃣ Trennzeichen mit awk -F festlegen
Bei einer Datei, deren Spalten nicht durch Leerzeichen getrennt sind, schreibst du das Zeichen hinter -F. Als wir $1 ohne -F aus der Kontenliste users.txt ausgaben, die wie /etc/passwd aufgebaut ist, kamen die meisten Zeilen als Ganzes heraus.
awk '{print $1}' users.txtroot:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
nobody:x:65534:65534:Kernel
user:x:1000:1000:Example
deploy:x:1001:1001:Deploy
backup:x:1002:1002::/home/backup:/sbin/nologinDas Standardtrennzeichen ist das Leerzeichen, daher hat eine nur durch Doppelpunkte verbundene Zeile nur ein Feld. Nur die Zeilen nobody, user und deploy, die in der Beschreibungsspalte ein Leerzeichen haben, werden dort getrennt.
Mit -F: als Doppelpunkt-Trennzeichen werden Kontoname ($1) und Login-Shell ($7) getrennt.
awk -F: '{print $1, $7}' users.txtroot /bin/bash
bin /sbin/nologin
daemon /sbin/nologin
nobody /sbin/nologin
user /bin/bash
deploy /bin/bash
backup /sbin/nologinKommagetrennte CSV-Dateien teilst du mit -F,. Gibst du Artikel und Menge aus den Verkaufsdaten sales.csv aus, wird auch die Kopfzeile (item qty) in der ersten Zeile so getrennt und erscheint mit.
awk -F, '{print $2, $3}' sales.csvitem qty
keyboard 2
mouse 5
monitor 1
keyboard 1
cable 10
mouse 2
monitor 2-F, passt nicht zu CSV-Dateien, bei denen Kommas in Spalten mit doppelten Anführungszeichen stehen. In quoted.csv mit Kommas in der Artikelspalte werden die Felder auch an den Kommas innerhalb der Anführungszeichen getrennt, sodass im zweiten Feld nur der vordere Teil des Artikelnamens bleibt.
awk -F, '{print $2}' quoted.csvitem
"cable
keyboardFür solche Dateien beschreibt das offizielle GNU-Awk-Handbuch die Variable FPAT. Schreibst du statt eines Trennzeichens die Form eines Feldes als regulären Ausdruck, ergibt eine Spalte in Anführungszeichen ein einziges Feld.
awk -v FPAT='([^,]*)|("[^"]*")' '{print $2}' quoted.csvitem
"cable, usb"
keyboardMehrere Trennzeichen schreibst du als regulären Ausdruck in eckige Klammern. Mit Doppelpunkt und Schrägstrich als Trennzeichen wird $NF zum letzten Namen im Pfad der Login-Shell (bash, nologin).
awk -F'[:/]' '{print $1, $NF}' users.txtroot bash
bin nologin
daemon nologin
nobody nologin
user bash
deploy bash
backup nologin3️⃣ Bedingungsmuster des awk-Befehls
Auch wenn du Felder wählst, werden alle Zeilen ausgegeben. Um nur die nötigen Zeilen zu behalten, setzt du vor die geschweiften Klammern eine Bedingung (ein Muster). Eine Zeichenkette zwischen Schrägstrichen wählt nur die Zeilen aus, die sie enthalten, und ohne Aktion wird die ganze Zeile ausgegeben.
awk '/wp-login/' access.log203.0.113.25 - - [29/Oct/2026:00:04:51 +0000] "POST /wp-login.php HTTP/1.1" 404 196 "-" "Mozilla/5.0 (X11; Linux x86_64)"
203.0.113.25 - - [29/Oct/2026:00:04:52 +0000] "POST /wp-login.php HTTP/1.1" 404 196 "-" "Mozilla/5.0 (X11; Linux x86_64)"Die ausgewählten Zeilen sind dieselben wie beim grep-Befehl, und awk kann aus diesen Zeilen direkt die Felder wählen und ausgeben. Übergibst du dieselben zwei mit grep gewählten Zeilen per Pipe an awk, bleiben nur IP und Statuscode.
grep wp-login access.log | awk '{print $1, $9}'203.0.113.25 404
203.0.113.25 404Feldwerte vergleichst du mit ==, !=, >, >=, <, <=. Wir haben nur die Zeilen mit dem Statuscode ($9) 404 gewählt und IP und Anfrage-URL ausgegeben.
awk '$9 == 404 {print $1, $7}' access.log203.0.113.25 /wp-login.php
203.0.113.25 /wp-login.php
203.0.113.25 /.envBeim Vergleich mit einer Zeichenkette setzt du den Wert in doppelte Anführungszeichen. Wir haben nur die Namen gewählt, deren zweites Feld pass ist.
awk '$2 == "pass" {print $1}' scores.txtalice
carol
daveZahlenvergleiche nutzt du, um nach Bereichen zu wählen, etwa bei Kontonummern (UIDs). Wählst du Konten mit einer UID ab 1000, ist neben den normalen Konten auch nobody mit der UID 65534 dabei.
awk -F: '$3 >= 1000 {print $1, $3}' users.txtnobody 65534
user 1000
deploy 1001
backup 1002Zwei Bedingungen verbindest du mit &&. Kommt die Bedingung unter 65534 hinzu, fällt nobody weg, und nur die drei normalen Konten und ihre Home-Ordner bleiben.
awk -F: '$3 >= 1000 && $3 < 65534 {print $1, $6}' users.txtuser /home/user
deploy /home/deploy
backup /home/backup[~] prüft, ob ein Feld zu einem regulären Ausdruck passt, [!~] prüft das Gegenteil. Wählst du Konten, deren Login-Shell ($7) auf bash endet, und Konten, deren Shell nicht nologin ist, erscheinen dieselben drei Konten.
awk -F: '$7 ~ /bash$/ {print $1}' users.txtroot
user
deployawk -F: '$7 !~ /nologin/ {print $1, $7}' users.txtroot /bin/bash
user /bin/bash
deploy /bin/bashEine NR-Bedingung wählt nach Zeilennummer. NR > 1 entfernt die CSV-Kopfzeile, und nur die Verkaufsdaten bleiben.
awk -F, 'NR > 1 {print $2, $3}' sales.csvkeyboard 2
mouse 5
monitor 1
keyboard 1
cable 10
mouse 2
monitor 2Auch die Ausgabe anderer Befehle kannst du per Pipe übergeben und genauso trennen. Bei der Auswahl von Dateigröße ($5) und Name ($9) aus der Ausgabe von ls -l war die erste Zeile leer, denn die erste Zeile von ls -l, [total 24], hat kein fünftes und neuntes Feld.
ls -l | awk '{print $5, $9}'
1567 access.log
79 quoted.csv
207 sales.csv
85 scores-copy.txt
85 scores.txt
315 users.txtMit NR > 1 fällt die erste Zeile weg, und nur Dateigrößen und Namen bleiben.
ls -l | awk 'NR > 1 {print $5, $9}'1567 access.log
79 quoted.csv
207 sales.csv
85 scores-copy.txt
85 scores.txt
315 users.txt4️⃣ awk BEGIN, END, Summen und Durchschnitte
Ein BEGIN-Block läuft einmal vor dem Lesen der ersten Zeile, ein END-Block einmal nach der letzten Zeile. Für eine Summe addierst du in jeder Zeile zu einer Variablen und gibst sie in END aus. Das folgende Diagramm zeigt die Reihenfolge, die awk pro Zeile durchläuft, wenn es die Beträge der Verkaufsdaten summiert.
$ awk -F, 'NR > 1 {t += $3 * $4} END {printf "total %.2f\n", t}' sales.csvDie Summe aller gesendeten Bytes ($10) im Zugriffslog betrug 41298 Bytes. Eine neu verwendete Variable beginnt leer (als Zahl 0), du musst sie also nicht auf 0 setzen.
awk '{sum += $10} END {print sum}' access.log41298Gibst du die Summe nicht in END, sondern in der Aktion für jede Zeile aus, erscheint nach jeder Zeile die bisherige Summe. Gibst du bei jeder Addition Zeilennummer und t aus, erscheinen sieben Zeilen ohne Kopfzeile, und die 886.3 in der letzten Zeile ist die Gesamtsumme.
awk -F, 'NR > 1 {t += $3 * $4; print NR, t}' sales.csv2 90
3 189.5
4 378.5
5 423.5
6 468.5
7 508.3
8 886.3Den Durchschnitt berechnest du in END, indem du die Summe durch die Zeilenzahl teilst. Die Summe der fünf Punktzahlen war 343, der Durchschnitt 68.6.
awk '{total += $3; n++} END {print total, n, total / n}' scores.txt343 5 68.6BEGIN nutzt du, um einmal eine Kopfzeile über den Ergebnissen auszugeben. Über Artikeln und Beträgen (Menge × Einzelpreis) erscheint die Zeile item total nur einmal.
awk -F, 'BEGIN {print "item", "total"} NR > 1 {print $2, $3 * $4}' sales.csvitem total
keyboard 90
mouse 99.5
monitor 189
keyboard 45
cable 45
mouse 39.8
monitor 378Das Ausgabetrennzeichen änderst du in BEGIN mit der Variablen OFS. Setzt du OFS auf ein Komma, steht an den Kommas von print ein Komma statt eines Leerzeichens, und die Kontenliste erscheint im CSV-Format.
awk 'BEGIN {FS = ":"; OFS = ","} {print $1, $3, $7}' users.txtroot,0,/bin/bash
bin,1,/sbin/nologin
daemon,2,/sbin/nologin
nobody,65534,/sbin/nologin
user,1000,/bin/bash
deploy,1001,/bin/bash
backup,1002,/sbin/nologinUm Spalten auszurichten, verwendest du printf. %-10s ist eine linksbündige Zeichenkette mit 10 Stellen, %3d eine Ganzzahl mit 3 Stellen und %8.2f eine Zahl mit 8 Stellen und zwei Nachkommastellen.
awk -F, 'NR > 1 {printf "%-10s %8.2f\n", $2, $3, $3 * $4}' sales.csvkeyboard 2 90.00
mouse 5 99.50
monitor 1 189.00
keyboard 1 45.00
cable 10 45.00
mouse 2 39.80
monitor 2 378.00Anders als print macht printf keinen Zeilenumbruch, schreibe daher [\n] ans Ende des Formats. Ohne [\n] laufen die Artikelnamen in einer Zeile zusammen.
awk -F, 'NR > 1 {printf "%s ", $2}' sales.csvkeyboard mouse monitor keyboard cable mouse monitor5️⃣ Log-Analyse und Optionen des awk-Befehls
🔲 Log-Analyse
Addierst du zu einer einzigen Variablen, erhältst du nur eine Summe. Um nach Client-IP oder Statuscode getrennt zu zählen, sammelst du die Werte in einem Array. n[$1]++ addiert 1 zum Array-Eintrag mit der IP als Schlüssel, und for (ip in n) in END holt die gesammelten Einträge einzeln heraus.
awk '{n[$1]++} END {for (ip in n) print n[ip], ip}' access.log | sort -rn4 192.0.2.10
3 203.0.113.25
3 198.51.100.7
2 192.0.2.44Die Reihenfolge von for (ip in n) ist nicht festgelegt (laut GNU-Awk-Handbuch), daher haben wir mit sort -rn nach Anfragezahl sortiert. 192.0.2.10 lag mit 4 Anfragen vorn.
Die Anzahl pro Statuscode zählst du genauso. 404 kam 3-mal vor, 500 einmal.
awk '{n[$9]++} END {for (s in n) print s, n[s]}' access.log | sort200 6
301 1
304 1
404 3
500 1Ziehst du nur die Statuscodes heraus und übergibst sie an sort und uniq -c, erhältst du dieselben Zahlen.
awk '{print $9}' access.log | sort | uniq -c 6 200
1 301
1 304
3 404
1 500Um nur Fehlerantworten zu sehen, setzt du eine Bedingung auf den Statuscode. Die Zeilen ab 400 waren drei Anfragen nach wp-login.php und .env und ein 500-Fehler.
awk '$9 >= 400 {print $9, $1, $7}' access.log404 203.0.113.25 /wp-login.php
404 203.0.113.25 /wp-login.php
404 203.0.113.25 /.env
500 198.51.100.7 /api/search?q=awkAuch die gesendeten Bytes pro IP summierst du in einem Array. 192.0.2.10 erhielt mit 31340 Bytes am meisten.
awk '{b[$1] += $10} END {for (ip in b) print b[ip], ip}' access.log | sort -rn31340 192.0.2.10
5120 192.0.2.44
4250 198.51.100.7
588 203.0.113.25Das Zeitfeld ($4) lässt sich als Zeichenkette vergleichen. Bei Zeilen mit gleichem Datum und Format entspricht die Zeichenfolge der Zeitfolge, daher haben wir nur die vier Anfragen von 00:05 bis kurz vor 00:10 gewählt.
awk '$4 >= "[29/Oct/2026:00:05" && $4 < "[29/Oct/2026:00:10" {print $4, $7}' access.log[29/Oct/2026:00:05:30 /contact.html
[29/Oct/2026:00:07:02 /old-page.html
[29/Oct/2026:00:07:15 /.env
[29/Oct/2026:00:09:48 /index.html🔲 Optionen des awk-Befehls
📌 Wichtige Optionen: Ergebnisse aus diesem Artikel
| Option | Was es tut | Ergebnis in diesem Artikel |
|---|---|---|
| -F fs | Legt das Trennzeichen für Eingabefelder fest | -F: trennt Kontoname ($1) und Login-Shell ($7) in users.txt, -F, gibt Artikel und Menge aus sales.csv samt Kopfzeile (item qty) aus |
| -v var=val | Weist einer Variablen vor dem Programmstart einen Wert zu | Die Shell-Variable min mit -v min=$min übergeben gibt sechs Zeilen mit mindestens 1000 gesendeten Bytes aus, mit -v FPAT=… ergibt eine Spalte in Anführungszeichen in quoted.csv ein Feld |
| -i inplace | Speichert die Ausgabe in der Originaldatei statt auf dem Bildschirm | Nach gawk -i inplace erscheint nichts auf dem Bildschirm, und die Kopie von scores.txt hat nur noch die Spalten Name und Punktzahl, mit -v inplace::suffix=.bak bleibt der vorherige Inhalt in einer .bak-Datei |
| --version | Gibt Versionsinformationen aus | Die erste Zeile von [awk --version] zeigt die Version GNU Awk 5 |
📎 Weitere Optionen: laut offiziellem Handbuch
| Option | Was es tut |
|---|---|
| -f program-file | Liest das AWK-Programm aus einer Datei statt aus dem ersten Befehlszeilenargument, -f kann mehrfach angegeben werden |
| -e program-text | Verwendet den Text in der Befehlszeile als AWK-Programmquelle, kombinierbar mit Bibliotheksfunktionen aus -f oder --include |
| -E file | Ähnlich wie -f, wird aber zuletzt verarbeitet und verhindert Variablenzuweisungen in der Befehlszeile, für #!-Skripte |
| --traditional | Läuft im Kompatibilitätsmodus und erkennt keine GNU-Erweiterungen |
| --posix | Aktiviert den Kompatibilitätsmodus mit weiteren Einschränkungen, erkennt etwa func, das Synonym für function, nicht |
| --lint | Warnt vor zweifelhaften oder schwer auf andere AWK-Implementierungen übertragbaren Konstrukten, mit --lint=fatal werden Warnungen zu fatalen Fehlern |
| --dump-variables | Schreibt eine sortierte Liste der globalen Variablen mit Typ und Endwert in eine Datei, ohne Dateiangabe in awkvars.out |
🔲 Simulator für den awk-Befehl
Im Simulator unten kannst du awk-Befehle selbst für dieselben Testdateien eingeben.
🔢 FAQ & empfohlene Inhalte
Sortieren
Linux-sort-Befehl: Dateien sortieren
Der sort-Befehl sortiert Dateiinhalte alphabetisch oder nach Zahlenwert. Nutze ihn im Anschluss, um awk-Summen von groß nach klein zu sehen.
Duplikate entfernen
Linux-uniq-Befehl
Der uniq-Befehl fasst aufeinanderfolgende gleiche Zeilen zu einer zusammen und zählt mit -c die Wiederholungen.
Dateien anzeigen
Linux-Befehle head und tail
Die Befehle head und tail zeigen nur die ersten oder letzten Zeilen einer Datei. Sie werden oft genutzt, um das Zugriffslog eines Servers zu prüfen.
ℹ️ Affiliate-Hinweis
Die Inhalte dieser Website enthalten Affiliate-Links. Kauft ein Besucher über einen dieser Links ein Produkt oder eine Dienstleistung, erhält die Website vom Verkäufer eine Provision. Der Betrag, den der Käufer zahlt(bei Aktionsrabatten sinkt er ↓), steigt dadurch nicht. Angegebene Preise, Rabatte und Lagerbestände entsprechen dem Stand bei Erstellung und können abweichen; prüfe sie daher vor dem Kauf beim Verkäufer. Produkte werden nach eigenen Kriterien ausgewählt und bewertet, und Provisionen beeinflussen weder die Reihenfolge noch den Inhalt der Bewertungen.