Awk ist eines der ältesten Tools in der Werkzeugkiste der Unix- und Linux-Benutzer. awk wurde in den 1970er Jahren von Alfred Aho, Peter Weinberger und Brian Kernighan (das A, W und K des Namens des Tools) entwickelt und wurde für die komplexe Verarbeitung von Textströmen entwickelt. Es ist ein Begleitwerkzeug zu sed, dem Stream-Editor, der für die zeilenweise Verarbeitung von Textdateien entwickelt wurde. Awk ermöglicht komplexer strukturierte Programme und ist eine vollständige Programmiersprache.
Dieser Artikel erklärt, wie man awk für strukturiertere und komplexere Aufgaben verwendet, einschließlich einer einfachen Seriendruckanwendung.
Awk-Programmstruktur
Ein awk-Skript besteht aus funktionalen Blöcken, die von {} umgeben sind (geschweifte Klammern). Es gibt zwei spezielle Funktionsblöcke, BEGIN und ENDE , die vor der Verarbeitung der ersten Zeile des Eingabestreams und nach der Verarbeitung der letzten Zeile ausgeführt werden. Dazwischen haben Blöcke das Format:
pattern { action statements }
Jeder Block wird ausgeführt, wenn die Zeile im Eingabepuffer mit dem Muster übereinstimmt. Wenn kein Muster enthalten ist, wird der Funktionsblock auf jeder Zeile des Eingabestroms ausgeführt.
Außerdem kann die folgende Syntax verwendet werden, um Funktionen in awk zu definieren, die von jedem Block aus aufgerufen werden können:
function name(parameter list) { statements }
Diese Kombination aus Mustervergleichsblöcken und -funktionen ermöglicht es dem Entwickler, awk-Programme für Wiederverwendung und Lesbarkeit zu strukturieren.
Wie awk Textstreams verarbeitet
Awk liest Text aus seiner Eingabedatei oder streamt Zeile für Zeile und verwendet ein Feldtrennzeichen, um ihn in eine Reihe von Feldern zu zerlegen. In awk-Terminologie ist der aktuelle Puffer ein Datensatz . Es gibt eine Reihe spezieller Variablen, die beeinflussen, wie awk eine Datei liest und verarbeitet:
- FS (Feldtrennzeichen):Standardmäßig ist dies ein beliebiges Leerzeichen (Leerzeichen oder Tabulatoren)
- RS (Datensatztrennzeichen):Standardmäßig wird ein Zeilenumbruch (\n )
- NF (Anzahl der Felder):Wenn awk eine Zeile parst, wird diese Variable auf die Anzahl der geparsten Felder gesetzt
- $0: Der aktuelle Rekord
- 1 $, 2 $, 3 $ usw.: Das erste, zweite, dritte usw. Feld aus dem aktuellen Datensatz
- NR (Anzahl der Datensätze):Die Anzahl der Datensätze, die bisher vom awk-Skript geparst wurden
Es gibt viele andere Variablen, die das Verhalten von awk beeinflussen, aber das reicht für den Anfang.
Awk-Einzeiler
Bei einem so mächtigen Tool ist es interessant, dass awk hauptsächlich aus einfachen Einzeilern besteht. Das vielleicht gebräuchlichste awk-Programm druckt ausgewählte Felder aus einer Eingabezeile aus einer CSV-Datei, einer Protokolldatei usw. Zum Beispiel druckt der folgende Einzeiler eine Liste von Benutzernamen aus /etc/passwd :
awk -F":" '{print $1 }' /etc/passwd
Wie oben erwähnt, $1 ist das erste Feld im aktuellen Datensatz. Das -F Option setzt die FS-Variable auf das Zeichen : .
Der Feldtrenner kann auch in einem BEGIN-Funktionsblock gesetzt werden:
awk 'BEGIN { FS=":" } {print $1 }' /etc/passwd
Im folgenden Beispiel jeder Benutzer, dessen Shell nicht /sbin/nologin ist kann gedruckt werden, indem dem Block eine Musterübereinstimmung vorangestellt wird:
awk 'BEGIN { FS=":" } ! /\/sbin\/nologin/ {print $1 }' /etc/passwd
Erweitertes awk:Seriendruck
Nachdem Sie nun einige der Grundlagen kennen, versuchen Sie, mit einem strukturierteren Beispiel tiefer in awk einzutauchen:Erstellen eines Seriendrucks.
Ein Seriendruck verwendet zwei Dateien, eine (in diesem Beispiel mit dem Namen email_template.txt ) mit einer Vorlage für eine E-Mail, die Sie senden möchten:
From: Program committee <[email protected]>
To: {firstname} {lastname} <{email}>
Subject: Your presentation proposal
Dear {firstname},
Thank you for your presentation proposal:
{title}
We are pleased to inform you that your proposal has been successful! We
will contact you shortly with further information about the event
schedule.
Thank you,
The Program Committee
Und die andere ist eine CSV-Datei (mit dem Namen proposals.csv ) mit den Personen, an die Sie die E-Mail senden möchten:
firstname,lastname,email,title
Harry,Potter,[email protected],"Defeating your nemesis in 3 easy steps"
Jack,Reacher,[email protected],"Hand-to-hand combat for beginners"
Mickey,Mouse,[email protected],"Surviving public speaking with a squeaky voice"
Santa,Claus,[email protected],"Efficient list-making"
Sie möchten die CSV-Datei lesen, die relevanten Felder in der ersten Datei ersetzen (die erste Zeile überspringen) und das Ergebnis dann in eine Datei namens acceptanceN.txt schreiben , Inkrementieren von N für jede Zeile, die Sie analysieren.
Schreiben Sie das awk-Programm in eine Datei namens mail_merge.awk . Anweisungen werden durch ; getrennt in awk-Skripten. Die erste Aufgabe besteht darin, die Feldtrennervariable und einige andere Variablen festzulegen, die das Skript benötigt. Sie müssen auch die erste Zeile in der CSV-Datei lesen und verwerfen, oder es wird eine Datei erstellt, die mit Dear firstname beginnt . Verwenden Sie dazu die Spezialfunktion getline und setzt den Datensatzzähler nach dem Lesen auf 0 zurück.
BEGIN {
FS=",";
template="email_template.txt";
output="acceptance";
getline;
NR=0;
}
Die Hauptfunktion ist sehr einfach:Für jede verarbeitete Zeile wird eine Variable für die verschiedenen Felder gesetzt – firstname , Nachname , E-Mail , und Titel . Die Vorlagendatei wird zeilenweise gelesen und die Funktion sub wird verwendet, um jedes Vorkommen der Sonderzeichenfolgen durch den Wert der entsprechenden Variablen zu ersetzen. Dann wird die Zeile mit allen vorgenommenen Ersetzungen in die Ausgabedatei ausgegeben.
Da Sie es mit der Vorlagendatei und einer anderen Ausgabedatei für jede Zeile zu tun haben, müssen Sie die Dateihandles für diese Dateien bereinigen und schließen, bevor Sie den nächsten Datensatz verarbeiten.
{
# Read relevant fields from input file
firstname=$1;
lastname=$2;
email=$3;
title=$4;
# Set output filename
outfile=(output NR ".txt");
# Read a line from template, replace special fields, and
# print result to output file
while ( (getline ln < template) > 0 )
{
sub(/{firstname}/,firstname,ln);
sub(/{lastname}/,lastname,ln);
sub(/{email}/,email,ln);
sub(/{title}/,title,ln);
print(ln) > outfile;
}
# Close template and output file in advance of next record
close(outfile);
close(template);
}
Sie sind fertig! Führen Sie das Skript in der Befehlszeile aus mit:
awk -f mail_merge.awk proposals.csv
oder
awk -f mail_merge.awk < proposals.csv
und Sie finden Textdateien, die im aktuellen Verzeichnis generiert wurden.
Erweitertes awk:Worthäufigkeitszählung
Eines der mächtigsten Features in awk ist das assoziative Array. In den meisten Programmiersprachen werden Array-Einträge normalerweise durch eine Zahl indiziert, aber in awk werden Arrays durch eine Schlüsselzeichenfolge referenziert. Sie könnten einen Eintrag aus der Datei proposals.txt hinterlegen aus dem vorherigen Abschnitt. Zum Beispiel in einem einzelnen assoziativen Array wie folgt:
proposer["firstname"]=$1;
proposer["lastname"]=$2;
proposer["email"]=$3;
proposer["title"]=$4;
Dies macht die Textverarbeitung sehr einfach. Ein einfaches Programm, das dieses Konzept verwendet, ist die Idee eines Worthäufigkeitszählers. Sie können eine Datei parsen, Wörter in jeder Zeile aufteilen (Interpunktion ignorieren), den Zähler für jedes Wort in der Zeile erhöhen und dann die 20 wichtigsten Wörter ausgeben, die im Text vorkommen.
Zuerst in einer Datei namens wordcount.awk , setzen Sie das Feldtrennzeichen auf einen regulären Ausdruck, der Leerzeichen und Satzzeichen enthält:
BEGIN {
# ignore 1 or more consecutive occurrences of the characters
# in the character group below
FS="[ .,:;()<>{}@!\"'\t]+";
}
Als nächstes iteriert die Hauptschleifenfunktion über jedes Feld, ignoriert alle leeren Felder (was passiert, wenn am Ende einer Zeile ein Satzzeichen steht) und erhöht die Wortanzahl für die Wörter in der Zeile.
{
for (i = 1; i <= NF; i++) {
if ($i != "") {
words[$i]++;
}
}
}
Nachdem der Text verarbeitet wurde, verwenden Sie schließlich die END-Funktion, um den Inhalt des Arrays auszugeben, und verwenden Sie dann die Fähigkeit von awk, die Ausgabe in einen Shell-Befehl zu leiten, um eine numerische Sortierung durchzuführen und die 20 am häufigsten vorkommenden Wörter auszugeben:
END {
sort_head = "sort -k2 -nr | head -n 20";
for (word in words) {
printf "%s\t%d\n", word, words[word] | sort_head;
}
close (sort_head);
}
Das Ausführen dieses Skripts auf einem früheren Entwurf dieses Artikels erzeugte diese Ausgabe:
[[email protected]]$ awk -f wordcount.awk < awk_article.txt
the 79
awk 41
a 39
and 33
of 32
in 27
to 26
is 25
line 23
for 23
will 22
file 21
we 16
We 15
with 12
which 12
by 12
this 11
output 11
function 11
Was kommt als nächstes?
Weitere Linux-Ressourcen
- Spickzettel für Linux-Befehle
- Spickzettel für fortgeschrittene Linux-Befehle
- Kostenloser Online-Kurs:RHEL Technical Overview
- Spickzettel für Linux-Netzwerke
- SELinux-Spickzettel
- Spickzettel für allgemeine Linux-Befehle
- Was sind Linux-Container?
- Unsere neuesten Linux-Artikel
Wenn Sie mehr über die awk-Programmierung erfahren möchten, empfehle ich dringend das Buch Sed und awk von Dale Dougherty und Arnold Robbins.
Einer der Schlüssel zum Fortschritt in der awk-Programmierung ist die Beherrschung von „erweiterten regulären Ausdrücken“. Awk bietet mehrere leistungsstarke Ergänzungen zur regulären Ausdruckssyntax von sed, mit der Sie vielleicht bereits vertraut sind.
Eine weitere großartige Ressource zum Erlernen von awk ist das GNU awk-Benutzerhandbuch. Es enthält eine vollständige Referenz für die eingebaute Funktionsbibliothek von awk sowie viele Beispiele für einfache und komplexe awk-Skripte.