awk/awk-ALTESEITE

Aus Mikiwiki
< awk
Wechseln zu: Navigation, Suche

awk ist eine Sprache zur Verarbeitung und Auswertung von Textdateien und besonders gut geeignet für die Listenbearbeitung. Die Bezeichnung awk setzt sich einfach aus den Anfangsbuchstaben der Nachnamen der Erfinder dieser Sprache zusammen: Aho, Kernighan und Weinberger.

Der awk zählt zu den grundsätzlichen Tools, die auf jedem UNIX-System verfügbar sein sollten. Er wird recht oft von anderen Programmen benutzt und sollte deshalb auf jeden Fall mit installiert werden. Unter Linux wird die GNU Implementierung gawk benutzt, die ausser allen im POSIX-Standard vorgesehenen Features auch die Erweiterungen aus SVR4 unterstützt.

Die Fähigkeiten des Programms:

  • Suchen und Ersetzen von Textmustern
  • Zugriff auf einzelne Felder
  • Bildung von Summen
  • Erkennung regulärer Ausdrücke
  • Vornahme von "BEGIN"- und "END"-Verarbeitungen
  • Zugriff auf die awk-Programmiersprache (beschrieben im Dokument "POSIX 1002.3 Command language and utilities standard")


Aufruf und Optionen

Ein awk-Skript besteht aus einzelnen Befehlen oder Befehlsblöcken, die entweder nur unter bestimmten Bedingungen oder für alle Zeilen der Eingabe ausgeführt werden. awk-Befehle können direkt von der Befehlszeile aufgerufen oder in Dateien gespeichert werden.

Arbeitsweise: awk bearbeitet nacheinander alle Sätze einer Datei, wobei als Satztrennzeichen gewöhnlich das newline-Zeichen angesehen wird.
Jeder Satz wird in Felder zerlegt, wobei der Feldtrenner eine Folge von Tabulatoren und Leerzeichen ist. Andere Feldtrenner können mit der Option "-F" oder "FS" eingestellt werden.
Der Zugriff auf bestimmte Felder eines Satzes erfolgt durch Angabe der Feldnummer mit vorangestelltem Dollarzeichen (z. B. "$3" für das dritte Feld), der gesamte Satz ist über "$0" ansprechbar.

Der awk ist ein Interpreter. Im einfachsten Fall ist das auszuführende Skript so kurz, dass man es gleich mit auf der Befehlszeile angeben kann:

awk [Optionen] [--] Programmtext Datei ...

Folgendes Beispiel gibt Namen der Benutzer und das jeweilige Home-Verzeichnis aus.

$ awk -F: '{print $5, $6}' /etc/passwd

Dabei gibt die Option "-F:" an, dass der Doppelpunkt als Trennzeichen zwischen Feldern aufgefasst werden soll. Das eigentliche awk-Programm besteht aus "{print $1, $6}". Die doppelten Anführungszeichen verstecken die im Skript enthaltenen Sonderzeichen vor der Shell. Die geschweiften Klammern gehören zum Skript!

Im awk werden Anweisungen, ähnlich der Shell, durch Strichpunkte getrennt. Damit kann man auch mehrere Anweisungen auf der Befehlszeile unterbringen. Trotzdem ist die Grenze der Übersichtlichkeit schnell erreicht und man schreibt das awk-Skript lieber in eine Datei. Der Skriptaufruf sieht dann so aus:

awk [Optionen] -f Skriptdatei [--] Datei ...

Die Programmdatei wird dabei entsprechend der Pfadangaben in der Umgebungsvariable "AWKPATH" gesucht. Ist diese Variable nicht gesetzt, so wird das aktuelle Verzeichnis und anschließend "/usr/local/share/awk" durchsucht.

Bei Bedarf kann auch direkt ein awk-Skript geschrieben werden, das als erste Zeile stets den Pfad zum awk-Interpreter enthalten muss.

#!/bin/awk -f
BEGIN { "Keine Angst vor awk!
  }

Grundzüge der Sprache

Programmablauf

Ein awk-Programm besteht aus einer Folge von pattern-action statements:

Suchmuster { action statements }

Ausserdem gibt es die Möglichkeit, Funktionen zu definieren:

function name(Parameterliste) { statements }

awk liest zunächst das komplette Programm ein und überführt es in eine interne Darstellung, die sich schneller ausführen lässt. Dann wird zunächst ein eventuell vorhandener "BEGIN"-Block abgearbeitet. Dieser Block umfasst die Statements, die mit dem speziellen Suchmuster "BEGIN" angegeben wurden. Hier kann man z.B. Variable initialisieren.

Dann werden alle Dateien in der angegebenen Reihenfolge zeilenweise gelesen. Für jede Zeile wird geprüft, mit welchen Suchmustern diese übereinstimmt. Die für diese Suchmuster angegebenen Aktionen werden ausgeführt.

Wenn alle Eingabezeilen verarbeitet sind, werden die Bestimmungen im "END"-Block abgearbeitet. Der "END"-Block ist durch das spezielle Suchmuster "END" gekennzeichnet. Hier werden häufig Summen ausgegeben.

Das folgende Beispiel druckt eine etwas schöner formatierte Liste aus der Datei "/etc/passwd", wobei nur Benutzer aufgeführt werden, die die bash als Login-Shell benutzen:

BEGIN {
  FS=":";
  print "Bash-Benutzer:"
  print "-------------------------------------------------------------------";
  printf "%-15s %-30s %s\n", "user-id", "Name", "Home";
  print "-------------------------------------------------------------------";
}
/\/bin\/bash/ {printf "%-15s %-30s %s\n", $1, $5, $6}
BEGIN {
  FS="^\"?|\"?,\"?|\"?$"
  printf "%7s %s\n", "Preis", "Titel"
  print "---------------------------------------------------"
  summe=0
  ARGV[1]="datei.csv"
  ARGC=2
}
{
  printf "%7.2lf %s\n", $3, $2
  summe+=$3
}
END {
  print "---------------------------------------------------"
  printf "%7.2lf\n", summe
}

Sätze, Felder und Variable

awk verwendet dynamische Variable. Diese brauchen nicht deklariert zu werden und können Strings oder Gleitkommawerte enthalten.

Sätze entsprechen normalerweise Zeilen, sie werden also durch das "LF" voneinander getrennt. Man kann aber auch durch Setzen der speziellen Variable "RS" einen anderen Satztrenner festlegen. Wird "RS" mit einer leeren Zeichenkette belegt, so werden Sätze durch Leerzeilen getrennt.

Beim Lesen eines Satzes wird dieser von awk in Felder zerlegt. Die Trennung erfolgt normalerweise durch Whitespace (Leerzeichen oder Tabulatoren), kann aber durch Setzen der Variable "FS" anders geregelt werden. Wird "FS" mit einer leeren Zeichenkette belegt, so wird aus jedem einzelnen Zeichen ein Feld.

Enthalten "RS" und "FS" mehr als ein Zeichen, so wird ihr Inhalt als regulärer Ausdruck aufgefasst. Oft findet man auch awk-Aufrufe folgender Gestalt:
awk -v 'FS=^\"?|\"?,\"?|\"?$' '{print $3, $2}' file.csv

Inhalt der Datei "file.csv":

"Harvest",19.90
"American Stars 'n Bars",24.50
"Unplugged",32.90
"Tonight's the night",16.00
"Deja vu",28.90
"Harvest Moon",32.90
"Old Ways",29.50

Hier wird die Zuweisung der Variable "FS" auf der Befehlszeile vorgenommen. Der oben angegebene Ausdruck zerlegt CSV-Dateien, wie sie von Excel oder dBase exportiert werden, in einzelne Felder.

Felder werden im Programm durch das Dollarzeichen mit nachgestellter Position im Eingabesatz bezeichnet. Dabei werden die Positionen mit 1 beginnend gezaehlt. "$7" bezeichnet also das siebte Feld. Mit "$0" erreicht man den gesamten Eingabesatz. Man kann auch Werte an Felder zuweisen. Auch ist es möglich, die Feldposition einer Variable zu entnehmen. Ausgeben des fünften Feldes:

n=5
print $n

Eingebaute Variable

awk verfügt über einige eingebaute Variable. Die wichtigsten davon sind:

ARGC Anzahl der Befehlszeilenparameter
ARGV Array der Befehlszeilenparameter. Die Indizes laufen von 0 bis ARGC -1. Durch ändern von ARGV kann man vom Skript aus weitere Dateien öffnen.
CONVFMT Das voreingestellte Format für Zahlen. Standardwert ist "%.6g".
ENVIRON Stellt die Umgebungsvariablen als assoziatives Array zur Verfügung. Ausgabe des Home-Verzeichnisses mit ENVIRON["HOME"]
ERRNO Text zum letzten aufgetretenen Fehler bei einer Dateioperation.
FIELDWIDTHS Wenn man diese Variable mit einer durch Leerzeichen getrennten Liste von Zahlen füllt, so werden die Felder nicht durch die in "FS" angegebenen Trennzeichen, sondern an den entsprechenden festen Positionen getrennt. Es kann z. B. verwendet werden, um vom Host per FTP übertragene Dateien in Felder zu zerlegen und weiterzuverarbeiten.
FNR Die Nummer des aktuellen Eingabesatzes. Ein awk '{print FNR, $0}' liefert ein Listing mit Zeilennummern.
IGNORECASE Hat diese Variable einen von Null verschiedenen Wert, so werden alle Stringvergleiche, das Trennen der Eingabe mit "FS" bzw. "RS" und die Auswertung regulärer Ausdrücke unabhängig von Gross- bzw. Kleinschreibung vorgenommen.
NF Liefert die Anzahl Felder im aktuellen Eingabesatz.
OFMT Das Standard-Ausgabeformat für Zahlen. Voreingestellt ist "%.6g".
OFS Das Feldtrennzeichen für die Ausgabe. Voreingestellt ist ein Leerzeichen.
ORS Das Satztrennzeichen für die Ausgabe. Voreingestellt ist "LF". Braucht man Zeilenenden im DOS-Format (CR+LF), kann man das (unter anderem) mit dem awk erledigen:

awk -v 'ORS=\r\n' '{print $0}'

Es existieren weitere Variablen, auf die hier nicht weiter eingegangen wird.

Typen

awk kennt keine echten Variablentypen, es wird nur mit Strings hantiert. Diese werden allerdings als Zahlen aufgefasst, wenn das im Zusammenhang sinnvoll ist. Soll die Auswertung als Zahl erzwungen werden, so addiert man eine 0.

Neben den einfachen Strings kennt awk noch assoziative Arrays. Die Indizes eines solchen Arrays sind (im Gegensatz zu C) Strings. Man kann auch mehrdimensionale Arrays verwenden.

Aktionen

Die Aktionen werden in geschweifte Klammern eingeschlossen. Aktionen können Zuweisungen, Verzweigungen und Schleifen enthalten. Die Syntax ist dabei ähnlich C.

Suchmuster und Aktionen

Die Anweisungen des awk bestehen aus dem Suchmuster und den in geschweifte Klammern eingeschlossenen Aktionen. Fehlt das Suchmuster, so werden die Aktionen für alle Eingabezeilen durchgeführt. Fehlt die Aktion, so wird die Eingabezeile unverändert ausgegeben. Der folgende "awk"-Aufruf entspricht einem einfachen grep:
$ awk '/reg. Ausdruck/' Datei

Das Script kann Kommentare enthalten. Diese beginnen mit dem Zeichen "#" und erstrecken sich bis zum Zeilenende. Leerzeilen sind zulässig. Ein Statement endet normalerweise am Zeilenende. Um Statements auf der nächsten Zeile fortzusetzen, maskiert man das Zeilenende mit einem umgekehrten Schrägstrich.

Suchmuster

Folgende Suchmuster sind möglich:

BEGIN Aktion vor Einlesen des ersten Satzes.
END Aktion nach Einlesen des letzten Satzes.
/rA/ Sätze, die den erweiterten regulären Ausdruck "rA" enthalten.
A op rA
A op A
Sätze für die der Vergleichsausdruck wahr ist.
Suchmuster && Suchmuster
Suchmuster || Suchmuster
Suchmuster ? Suchmuster : Suchmuster
(Suchmuster)
! Suchmuster
Suchmuster, Suchmuster

"BEGIN" und "END" wurden schon erläutert. Die regulären Ausdrücke entsprechen denen von egrep. Vergleichende Ausdrücke können umfangreicher sein. Man kann z.B. testen, ob bestimmte Felder einem regulären Ausdruck entsprechen. Die Operatoren "&&", "||", "!" und "?" werden in Analogie zu C angewandt (logisches Und, Oder, Negation und wahlweise Ausführung). Durch Klammern kann man die Reihenfolge der Ausführung bestimmen. Zwei durch Komma getrennte Suchmuster ermitteln einen Bereich von Zeilen, wobei die erste vom ersten, die letzte vom zweiten Suchmuster bestimmt wird.


Operatoren

(...) Gruppierung
$ Feldreferenz
= Variablenzuweisung
++ -- Inkrement und Dekrement, in postfix- oder präfix-Notation
^ Potenzieren
+ - ! unäres plus, minus und logische Negation
+ - * / % Mathematische Operatoren (Addition, Subtraktion, Multiplikation, Division, Modulo-Funktion)
space Stringverkettung
< > <= >= == != Vergleichsoperatoren
~ !~ match-Operatoren: Vergleich mit regulären Ausdrücken
in Test auf Enthaltensein in einem Array
! && || Logische Operatoren (Nicht, Und, Oder)
?: Bedingter Ausdruck, wie in C
= += -= *= /= %= ^= Zuweisung, wie in C

Verfügbare Variablen

NR Nummer des aktuellen Satzes.
NF Anzahl der Felder des aktuellen Satzes.
FS Eingabe-Feldtrennzeichen.
RS Eingabe-Satztrennzeichen.
$i, 1 <= i <= 99 i-tes Feld des aktuellen Satzes.
$0 Der gesamte aktuelle Satz.
$1, $2, $3 Erstes, zweites, drittes Feld des aktuellen Satzes.
length Länge des Satzes.
OFS Ausgabe-Feldtrennzeichen.
ORS Ausgabe-Satztrennzeichen.
FILENAME Name der gerade bearbeiteten Datei.

Steueranweisungen

Die meisten Steueranweisungen haben eine direkte Entsprechung in C:

  • if (Bedingung) Anweisung [ else Anweisung ]
  • while (Bedingung) Anweisung
  • do Anweisung while (Bedingung)
  • for (Ausdruck1; Ausdruck2; Ausdruck3) Anweisung
  • for (Variable in Array) Anweisung
  • break
  • continue
  • delete Array[Index]
  • delete Array
  • exit [ Ausdruck ]
  • { Anweisungen }

Ein/Ausgabe-Anweisungen

close(Datei) Datei (oder pipe) schliessen
getline nächste Zeile in $0 laden
getline < file Nächste Zeile aus Datei "file" lesen.
getline Variable Nächste Zeile in Variable, statt $0, laden
getline Variable < file Zeile aus Datei "file" in Variable laden
next Nächste Zeile lesen und ab Anfang des Scriptes bearbeiten
nextfile Aktuelle Datei schliessen und mit nächster fortfahren.
print Gibt den aktuellen Satz aus
print Ausdrucksliste Gibt Ergebnis der Ausdrücke aus.
print Ausdrucksliste > file Schreibt Ergebnis der Ausdrücke in Datei "file"
printf Format, Ausdrucksliste Gibt Ergebnisse formatiert aus
printf Format, Ausdrucksliste > file formatierte Ausgabe in Datei "file"
system(Befehlszeile) Führt einen Befehl aus
fflush([Datei]) Erzwingt das Schreiben der Puffer

Andere Dateiumleitungen als ">" sind ebenfalls erlaubt. ">>" hängt Daten an eine bestehende Datei an, "|" schreibt die Daten in eine Pipe.

Das Format für printf stimmt im wesentlichen mit dem für die entsprechende C-Funktion überein.

Stringfunktionen

Hier werden nur einige der Stringfunktionen erläutert, genaueres erfährt man in der Manual Page.

gensub(r, s, h [, t]) Ersetzt einige oder alle Vorkommen eines einem regulären Ausdruck entsprechenden Teilstrings (entspricht substitute im sed bzw. vi).
gsub(r, s [, t]) Macht dasselbe wie "gensub", nimmt die Ersetzung aber direkt im entsprechenden Feld vor und liefert die Anzahl vorgenommener Ersetzungen.
index(s, t) Liefert die Position der Zeichenkette s in t, bzw. 0, wenn s nicht in t enthalten ist.
length([s]) Liefert die Länge von s. Ohne Angabe von s erhält man die Länge des Eingabesatzes $0
match(s,r) Liefert die Position in s, ab der der reguläre Ausdruck r passt, anderenfalls 0. Diese Funktion wird häufig dazu genommen, in einem Suchmuster zu bestimmen, ob ein Feld einem regulären Ausdruck entspricht. Beispiel:

$ awk -F: 'match($7,"/bin/bash")' /etc/passwd

split(s,a,[, r]) Zerlegt den String "s" in ein Array "a" und liefert die Anzahl Teilstrings. Die Zerlegung erfolgt an Hand des regulären Ausdrucks "r". Falls dieser weggelassen wird, verwendet awk den Inhalt der Variable "FS".
sprintf(Format, Ausdrucksliste) Liefert formatierte Ergebnisse der Ausdrücke als String.
sub(r, s [, t]) wie "gsub", nimmt aber nur die erste Ersetzung vor.
substr(s, i [, n]) Liefert den "n" Zeichen langen Teilstring von "s" ab Position "i". Wird "n" weggelassen, so erhält man den Rest von "s" ab Position "i".

Verwendung

Ausgabe aller Zeilen der Datei "file".
$ awk '{ print }' file

Ausgabe aller Zeilen der Datei "file" wobei die wichtigsten awk-Variablen in die Datei "awkvars.out" geschrieben werden.
$ awk --dump-variables '{ print }' file

Ausgabe der laufenden Nummer (NR) sowie der Anzahl der Felder (NF) für jede Zeile der Datei "file".
$ awk '{ print NR, NF }' file

Ausgabe jeder Zeile mit vorangestellter Satznummer.
$ awk '{ print NR, $0 }' file

Ausgabe der ersten Spalte aller Sätze von Datei "file".
$ awk '{ print $1 }' file

awk erhält den Inhalt der Variable "$USER" als Befehlsparameter. Der erste übergebene Parameter ("$1") wird mit etwas Text ausgegeben, wobei jeweils ein "|"-Zeichen als Trenner eingesetzt wird.
$ echo $USER | awk '{ print "Hallo " $1 "!" }'

awk erhält den Text "A B C D" und gibt davon nur das dritte und vierte Feld aus, getrennt durch ein Leerzeichen (" "):
$ echo "A B C D" | awk '{ print $3 " " $4 }'

Die Ausgabe von cal (für den Monat Märzt 2007) wird von awk mit der Zeilennummer ("NR") und der Anzahl Felder ("NF") ergänzt und zeilenweise ausgegeben ("$0").
$ cal 03 2007 | awk '{ print NR " | " NF " | " $0 }'

Finden aller Zeilen der Datei "file", die die Zeichenkette "Asia" enthalten und Ausgabe über awk mit Satznummer sowie Ausgabe der Felder1, 2 und 3.
$ egrep 'Asia' file | awk '{ print NR, $1, $2, $3 }'

Falls in Feld 4 die Zeichenkette "Asia" steht, werden Feld 1 und 2 der Datei "file" ausgegeben.
$ awk '$4 == "Asia" { print $1, $2 }' file

Dieselbe Aktion ist in Hochkommas eingeschlossen, um Sonderzeichen wie $ vor einer Auswertung durch die Shell zu schützen. Alternativ könnte auch jedes Sonderzeichen durch den Gegenschrägstrich entwertet werden.
$ awk \$4\ \=\=\ \"Asia\"\ \{\ print\ \$1,\ \$2\ \} file

Wird in der Befehlszeile keine Datei angegeben, so erwartet awk seine Eingabedaten von der Standard-Eingabe. Durch Einsatz des Bindestrichs kann aber auch explizit angegeben werden, dass awk von der Standard-Eingabe lesen soll.

Als Eingabe wird zunächst die Datei "file" und danach die Standard-Eingabe benutzt.
$ awk '{ print $3, $4 }' file -

Aufruf von awk wobei die Anweisungen in der Datei "script.awk" enthalten sind und auf die Datei "file" angewendet werden.
$ awk -f script.awk file

Ausgabe aller Zeilen aus Datei "file", in denen Feld 3 einen Wert höher als 500 aufweist.
$ awk '$3 > 500 { print }' file

Alphanumerische Vergleiche.
$ awk '$1 >= "S" { print }' file
$ awk '$1 >= "s" { print }' file
$ awk '$1 == $4 { print }' file

Ausgabe der dritten Spalte aller Sätze von Datei "file", in denen das "Suchmuster" vorkommt.
$ awk '/Suchmuster/ { print $3 }' file
Beispiel: Ausgabe der Benutzer, die die Bash benutzen:
$ awk '/bash/ { print $0 }' /etc/passwd

Ausgabe aller Zeilen, welche die Zeichenkette "US" enthalten.
$ awk '/US/ { print }' file

Ausgabe des ersten Felds aller Zeilen, in den Feld 4 die Zeichenkette "As" enthält.
$ awk '$4 ~ /As/ { print $1 }' file

Ausgabe der dritten Spalte aller Sätze von Datei "file", in denen ein "P" und oder ein "g" vorkommt.
$ awk '/[Pg]/ { print $3 }' file

Ausgabe der dritten Spalte aller Sätze von Datei "file", deren zweite Spalte ein "0" vorkommt.
$ awk '$2 ~ /0/ { print $3 }' file

Ausgabe aller Spalten der Datei "file", wobei das Suchmuster "pattern1" durch die Zeichenfolge "pattern2" ersetzt wird.
$ awk '{ gsub(/pattern1/,"pattern2"); print $0 }' file

Ausgabe des Inhalts der Datei "file", wobei jede Zeile durchnumeriert wird.
$ awk '{ print NR, $0 }' file

Ausgabe der Anzahl der in der Datei "file" enthaltenen Sätze.
$ awk 'END { N = FILENAME ; print N, "hat", NR, "Sätze." }' file

Ausgabe aller Sätze der Datei "file" mit vorangestellter Satznummer.
$ awk '{ print $1, $2 * $4 }' file

Ausgabe der Spalten 1, 2 und 3 aller Sätze der Datei "file", wobei als Ausgabe-Feldtrennzeichen der Doppelpunkt verwendet wird.
$ awk 'BEGIN { OFS = ":" } { print $1, $2, $3 }' file

Ausgabe der Spalten 2 und 6 (getrennt durch ein Leerzeichen) der Ausgabe des Befehls date:
$ date | awk '{ print $2 " " $6 }'

Ausgabe der ersten Spalte aller Sätze von Datei "file", bei deren dritte Spalte den Wert "0" enthält.
$ awk '$3 == 0 { print $1 }' file

Ausgabe des ersten Feldes (der Gruppenname) der durch Doppelpunkte getrennten Felder der Datei "/etc/group".
$ awk -F':' '{ print $1 }' /etc/group

Ausgabe der mittels Kommas, Tabulatoren oder Leerzeichen getrennten Felder der Datei "file".
$ awk -F'[,[:blank:]]' '{ print $1 $2 $3 }' file

Ausgabe der ersten (Loginname) und dritten (Gcos-Feld) Spalte aus der Datei "/etc/passwd". Die Zeilen werden nur ausgegeben, wenn die numerische UID "0" ist.
$ nawk -F: '$3 == 0 { print $1, $5 }' /etc/passwd

Ausgabe des dritten und vierten Feldes der durch Doppelpunkte getrennten Felder der Datei "/etc/group". print liefert dabei eine unformatierte Ausgabe.
$ awk -F':' '{ print $3 $4 }' /etc/group

Ausgabe des ersten Feldes (der Gruppenname) der durch Doppelpunkte getrennten Felder 3 (Gruppen-ID) und 4 (Benutzer) der Datei "/etc/group". Dier Formatierung der Ausgabe findet dabei mit dem Befehl "printf()" statt, der wie in der Programmiersprache C funktioniert.
$ awk -F':' '{ printf("%5s %s\n", $3, $4 }' /etc/group

Ausgabe aller Felder der durch Doppelpunkte getrennten Felder der Datei "/etc/group", wobei das zweite Feld nicht ausgegeben werden soll und ihm deshalb eine leere Zeichenkette zugewiesen wird.
$ awk -F':' '{ $2=""; print }' /etc/group

Ausgabe der zweiten Spalte aller Sätze von Datei "file", deren Wert höher als "6" ist.
$ awk '$2 > 6' file

Prüfung jeder Zeile der Ausgabe von "ps -ax", ob die Prozessnummer ("$1") unter 100 liegt. Trifft dies zu, werden die Prozessnummer, ein Leerzeichen und der Befehlsname ("$5") ausgedruckt.
$ ps -ax | awk '$1 > 100 { print $1 " " $5 }'

Prüfung jeder Zeile der Ausgabe von "ps -ax", ob die Prozessnummer ("$1") zwischen 50 und 60 liegt. Trifft dies zu, werden die Prozessnummer, ein Leerzeichen und der Befehlsname ("$5") ausgedruckt.
$ ps -ax | awk '$1 > 50 && $1 < 60 { print $1 " " $5 }'

Anzeige der für die Schnittstelle "eth0" eingetragenen IP-Adresse.
$ /sbin/ifconfig eth0 | /usr/bin/awk ' /inet [aA]dd?r/ {print substr ($2, index ($2, ":") + 1) }'

Ausgabe der Länge der längsten Zeile von Datei "file":
$ awk '{ if (length($0) > max) max = length($0) } END { print max }' file

Ausgabe der ersten Spalte aller Zeilen von Datei "file".
$ awk 'BEGIN { print "Wir zählen Zeilen!"; anzahl=0 } { print $1; anzahl++} END {print "Das waren " anzahl " Zeilen." }' file

Skript "pstat.awk" zur Auswertung des Aufrufs "ps -aux | awk -f pstat.awk". Jede Eingabezeile wird untersucht, ob es sich um eine Kopfzeile handelt ( $1 != "USER" ). Trifft dies nicht zu, wird auf die Variablen "cpu" und "mem" das betreffende Feldelement ("$3, $4") addiert und die Anzahl verarbeiteter Zeilen inkrementiert.

$ BEGIN {
print "Systemstatus:"
}
{
if ($1 != "USER")
{
cpu += $3
mem += $4
procs++
}
}
END {
print cpu "% CPU " mem "% MEM " procs " PROCS"
}

Das folgende Beispiel bildet Summen nach Spalten und gibt diese und ein Gesamttotal aus:

$ cat > sum
111 222 333
444 555 666
777 888 999
$ cat > sum.awk
BEGIN { n = 3 }
        { for (i=1;i<=n;i++)
                sum[i] += $i
        }
        END { for (i=1;i<=n;i++) {
                printf "%6g ",sum[i]
                total += sum[i]
                }
                printf "; Total = %6g\n",total
        }
CTRL D
$ nawk -f sum.awk sum

1332 1665 1998 ; Total = 4995

Assoziative arrays

Assoziative arrays sind arrays, deren Index ein String ist (unter Perl bekannt als "hash"). Im folgenden Beispiel soll die Datei "sum2" so verarbeitet werden, dass pro Name eine Zeile mit einem Total ausgegeben wird. Die Anweisungen in der Datei "sum2.awk" tun genau das mittels eines assoziativen arrays.

$ cat > sum2
Erich 400
Rita 200
Paul 100
Maria 400
Rita 300
Erich 200
Paul 500
Rita 400
$ cat > sum2.awk
{ sum [$1] += $2 }
END { for (name in sum) print name , sum[name] }
$ nawk -f sum2.awk sum2
Maria 400
Erich 600
Rita 900
Paul 600

Einlesen eines beliebigen Textes (im Beispiel die Datei "/etc/passwd"), Anlegen einer Liste mit Worten (Index) und Ablegen der Anzahl (value) in einem assoziativen array. Anschliessend wird eine Liste mit dem Wort und seiner Häufigkeit ausgegeben:

$ cat > zaehl.awk
{ for (i=1;i<=NF;i++) num[$i]++ }
END { for (word in num) print word, num[word] }
$ nawk -f zaehl.awk /etc/passwd
lp:x:71:8:Line 1
Admin:/usr/spool/lp: 1
user:/usr/kurs4:/usr/bin/ksh 1
...

Sortieren:

$ nawk -f zaehl.awk absolute | sort -nr +1
I 10
the 8
of 5
have 3
and 3
...

Sortieren, wobei der Feldtrenner ";" nicht beachtet wird (kann auch direkt ins Skript geschrieben werden:
BEGIN { IFS=; } ):

$ nawk -F: -f zaehl.awk /etc/passwd
No Access User 1
2 2
 13
nobody 1
3 2
4 3
root 1
...

Beispiele

Auftrennung der einzelnen Zeilen der Datei "/etc/passwd".

$ cat /etc/passwd | awk -F : '{ print $1" "$2" "$3" "$4}'
root x 0 0
bin x 1 1
...

Im aktuellen Verzeichnis wird jedes Verzeichnis als "Verzeichnis: <Verzeichnisname>" und jede Datei als "Datei: <Dateiname>" ausgegeben.

$ ls -l | awk ' /^d/ { print "Verzeichnis: " $8 } /^-/ { print "Datei: " $8 }'

Im aktuellen Verzeichnis wird jedes Verzeichnis als "<Verzeichnisname>: Verzeichnis" und jede Datei als "<Dateiname>: Datei" ausgegeben.

$ ls -l | awk ' /^d/ { printf("%-15s%-15s\n", $8, ": Verzeichnis") } /^-/ { printf ("%-15s%-15s\n", $8, ": Datei") }'

Anzeige jeder Zeile der Datei "ascii.c", die länger als 30 Zeichen ist.

$ awk 'length($0) > 30' /etc/passwd

Anzeige jeder Zeile der Datei "file", die mindestens ein Feld aufweist (in diesem Fall ein Zeichen), d. h. durch Umleitung der Ausgabe in die Datei "noemptylines" können rasch alle Leerzeilen gelöscht werden.

awk 'NF > 0' file > noemptylines

Berechnung der Dateigrösse in Byte.

$ ls -l /etc/passwd | awk '{ x += $5 } END { print "Byte: " x }'
Byte: 1232

Ein kleines C-Programm, das auf der Konsole den ASCII-Code von 33-127 ausdruckt (7 Bit). Zuerst wird die Textdatei "ascii.c" geschrieben, danach mit gcc kompiliert. Die ausführbare Datei heisst dann "asc".

$ vi ascii.c
#include <stdio.h>
#include <stdlib.h>
void get_ascii(void) {
  int i; int j = 33; int k = 40;
  int step = (k-j) + 1;
  for (i = 0; i < 12; ++i) {
    for ( ; j <= k; ++j) {
      if (j == 128) {
        break;
      }
    printf("%4d= %c",j,j);
    }
  j = (k + 1);
  k += step;
  printf("\n\n");
  }
}
int main(void) {
  printf("\n");
  get_ascii();
  printf("\n");
}
$ gcc -o asc ascii.c
$ ./asc
  33= !  34= "  35= #  36= $  37= %  38= &  39= '  40= (

  41= )  42= *  43= +  44= ,  45= -  46= .  47= /  48= 0

  49= 1  50= 2  51= 3  52= 4  53= 5  54= 6  55= 7  56= 8

  57= 9  58= :  59= ;  60= <  61= =  62= >  63= ?  64= @

  65= A  66= B  67= C  68= D  69= E  70= F  71= G  72= H

  73= I  74= J  75= K  76= L  77= M  78= N  79= O  80= P

  81= Q  82= R  83= S  84= T  85= U  86= V  87= W  88= X

  89= Y  90= Z  91= [  92= \  93= ]  94= ^  95= _  96= `

  97= a  98= b  99= c 100= d 101= e 102= f 103= g 104= h

 105= i 106= j 107= k 108= l 109= m 110= n 111= o 112= p

 113= q 114= r 115= s 116= t 117= u 118= v 119= w 120= x

 121= y 122= z 123= { 124= | 125= } 126= ~ 127=

Abschiessen aller Prozesse, welche die Zeichenfolge "Z39O" enthalten:

for i in $(ps -ef | grep Z39O | awk '{ print $2 }'); do kill -15 $i; done

Wenn die Zeilenzahl grösser als 4 ist, ausserdem die Spalte 12 grösser als 1 und die Spalte 14 grösser als 0 und Spalte 7 das Wort "Afrika" enthält, so werden die Zeilen ausgegeben.

awk 'NR > 4 {
  if ($12>1) {
    if ($14>0) {
      if ($7=="Afrika") { print $12, $14 }
    }
  }
}' afrika.csv  

Alternativ dazu kann der ganze Befehl auch in einer Zeile geschrieben werden:

awk 'NR>4&&$12>1&&$14>0&&$7=="Afrika"{print $12, $14}' afrika.csv

Beispiele 2

Beispieldatei "file":

$ more file
Tom     6.20    22
Dick    4.45    5
Harry   6.15    12
Jim     4.85    0
Jake    5.20    0

Ausgabe des Texts "hallo, hallo".

$ awk 'BEGIN { printf("hallo, hallo\n") }'
hallo, hallo

Ausgabe aller Zeilen der Datei "file", die in der zweiten Spalte ("$2") einen Wert kleiner als 5 aufweisen. Ausgegeben werden rechtsbündig die ersten zehn Zeichen ("%10s") der ersten Spalte ("$1"), begrenzt durch Doppelpunkte.

$ awk '$2 < 5 { printf(":%10s:\n", $1) }' file
:      Dick:
:       Jim:

Ausgabe aller Zeilen der Datei "file", die in der zweiten Spalte ("$2") einen Wert kleiner als 5 aufweisen. Ausgegeben werden rechtsbündig die ersten zehn Zeichen ("%-10s") der ersten Spalte ("$1"), begrenzt durch Doppelpunkte.

$ awk '$2 < 5 { printf(":%-10s:\n", $1) }' file
:Dick      :
:Jim       :

Ausgabe aller Zeilen der Datei "file", die in der zweiten Spalte ("$2") einen Wert grösser als 6 aufweisen. Ausgegeben werden die Werte der zweiten Spalte als Fliesskommazahlen auf zwei Stellen genau. (ACHTUNG: Damit die Fliesskommazahlen richtig berechnet werden muss die Variable LANG richtig belegt sein!)

$ awk '$2 > 6 { printf("%6.2f\n", $2) }' file
  6.20
  6.15

Erstellung einer Gehaltsliste basierend auf den Werten der Datei "file". Falls die dritte Spalte nicht den Wert "0" aufweist ("$3 != 0"), so wird erst linksbündig die erste Spalte und danach rechtsbündig eine Fliesskommazahl auf zwei Stellen genau ausgegeben, die sich aus dem multiplizierten Wert der Spalten zwei und drei ("$2 * $3") ergibt.

$ awk 'BEGIN { print "Gehaltsliste" } $3 != 0 { printf("%-7s%7.2f\n", $1, $2 * $3) }' file
Gehaltsliste
Tom     136.40
Dick     22.25
Harry    73.80

Berechnung des Durchschnittslohns ausgehend von den Werten in Spalte 2 ("$2") der Datei "file".

$ awk 'BEGIN { printf("Durchschnittslohn:") }
>            { sum = sum + $2
>              i = i + 1
>            }
>      END   { if ( i != 0 ) {
>              printf("%6.2f\n", sum / i)
>              }
>            }' file
Durchschnittslohn:  5.37

While-Schleife.

$ awk 'END { i =1
>            while ( i <= 5 ) {
>            printf("%2d", i)
>            i = i + 1
>            }
>            printf("\n") }' file
 1 2 3 4 5

For-Schleife. Hier wird zuerst der Initialisierungswert gesetzt ("i = 1"), dann die Bedingung für den Schleifenabbruch ("i <= 5") und schliesslich der Schleifenzähler ("i = i + 1").

$ awk 'END { for( i = 1; i <= 5; i = i + 1) {
>            printf("%2d", i)
>            }
>            printf("\n") }' file
 1 2 3 4 5

awk besitzt folgende Funktionen zur Bearbeitung von Zeichenketten:

  • length("string") - Länge der Zeichenkette "string")
  • index("string1","string2") - Position von "string1" in "string2"
  • substr("string",p[,1]) - Aus "string" werden ab Position "p" "1" Zeichen oder alle herausgenommen

Prüfung der Zeilenlänge mit Ausgabe der Nummer der Zeilen, die länger als die angegebene Anzahl Zeichen sind.

$ awk '{ if (length >= 10) {
>        printf("Zeile %d zu lang\n", NR)
>        }
>      }' file

Anzeige in an welcher Position sich in Spalte 1 ("$1") in jeder Zeile der Datei "file" das Zeichen "a" befindet.

$ awk '{ printf("a an Stelle %d\n", index($1,"a")) }' file
a an Stelle 0
a an Stelle 0
a an Stelle 2
a an Stelle 0
a an Stelle 2

Anzeige der Buchstaben 1 bis 3 ("1,3") der ersten Spalte ("$1") in jeder Zeile der Datei "file".

$ awk '{ printf("Erste drei Buchstaben: %s\n", substr($1,1,1)) }' file
Anfangsbuchstabe T
Anfangsbuchstabe D
Anfangsbuchstabe H
Anfangsbuchstabe J
Anfangsbuchstabe J

awk kann auch Vektoren verarbeiten. Die Vektorelemente werden mit "Vektorname[index]" angesprochen.

Anzeige des zweiten Feldes ("zeile[2]") jeder Zeile der Datei "file".

$ awk '{ for( i = NF; i > 0; i = i - 1 ) {
>          zeile[i] = $i
>          }
>        printf("Zweites Feld: %s\n", zeile[2])
>      }' file
Zweites Feld: 6.20
Zweites Feld: 4.45
Zweites Feld: 6.15
Zweites Feld: 4.85
Zweites Feld: 5.20

Mit der Funktion "split" kann eine beliebige Zeichenfolge in einem Vektor abgespeichert werden:

  • split("string",Vektor[,Trenner]) teilt die Zeichenkette "string" an den durch "Trenner" gekennzeichneten Stellen auf und legt die einzelnen Elemente in "Vektor" ab. Standardtrennzeichen ist FS. Der Rückgabewert von "split" ist die Anzahl der Vektorelemente.
$ awk 'BEGIN { Z = "eins:zwei:drei" }
>      END   { n = split(Z, zahl, ":")
>              for (i = 1; i <= n; i = i + 1) {
>                printf("Im Feld %d steht %s\n", i, zahl[i])
>              }
>            }' file

Die Indizes für die Vektorelemente können beliebige Zeichenketten sein. Werden als Indizes keine Zahlen gewählt, so können solche Vektoren mit einer besonderen for-Schleife durchlaufen werden:

$ awk '     { for(i = 1; i <= length; i = i + 1) {
>               z=substr($0, i, 1)
>               zeichen[z] = zeichen[z] + 1
>             }
>           }
>       END { for ( z in zeichen ) {
>               printf("%s kommt %2d-mal vor\n", z, zeichen[z])
>             }
>           }' file
4 kommt  3-mal vor
5 kommt  5-mal vor
i kommt  2-mal vor
...

Weblinks