Erlernen von Linux-Befehlen: awk
Im Fall dieses Artikels könnte der Titel "Learning Linux Commands: awk" ein wenig irreführend sein. Und das liegt daran, dass awk mehr als ein Befehl ist, es ist eine eigenständige Programmiersprache. Sie können awk-Skripte für komplexe Operationen schreiben oder awk über die Befehlszeile verwenden. Der Name steht für Aho, Weinberger und Kernighan (ja, Brian Kernighan), die Autoren der Sprache, die 1977 gestartet wurde, daher teilt sie den gleichen Unix-Geist wie die anderen klassischen *nix-Dienstprogramme.
Wenn Sie sich an die C-Programmierung gewöhnen oder sie bereits kennen, werden Sie einige vertraute Konzepte in awk sehen, zumal das "k" in awk für dieselbe Person steht wie das "k" in K&R, der C-Programmierbibel. Sie benötigen einige Kommandozeilenkenntnisse in Linux und möglicherweise einige Skripting-Grundlagen, aber der letzte Teil ist optional, da wir versuchen werden, für jeden etwas anzubieten. Vielen Dank an Arnold Robbins für all seine Arbeit, die er in awk investiert hat.
In diesem Tutorial lernen Sie:
- Was macht
awk? Wie funktioniert das? AWKGrundbegriffe- Erfahren Sie,
wie Sie awküber Befehlszeilenbeispiele verwenden
Kennenlernen des awk-Befehls durch verschiedene Befehlszeilenbeispiele unter Linux
Was macht awk?
AWK ist ein Dienstprogramm/eine Sprache, die für die Datenextraktion entwickelt wurde. Wenn das Wort "Extraktion" Ihnen bekannt vorkommt, dann sollte es das auch, denn awk war einst Larry Walls Inspiration, als er Perl erschuf. awk wird oft mit sed verwendet, um nützliche und praktische Textmanipulationsaufgaben durchzuführen, und es hängt von der Aufgabe ab, ob Sie awk oder Perl verwenden sollten, aber auch von den persönlichen Vorlieben. Genau wie sed liest awk eine Zeile nach der anderen, führt je nach der Bedingung, die Sie ihm geben, eine Aktion aus und gibt das Ergebnis aus.
Eine der einfachsten und beliebtesten Anwendungen von awk ist das Auswählen einer Spalte aus einer Textdatei oder der Ausgabe eines anderen Befehls. Eine Sache, die ich mit awk zu tun pflegte, war, wenn ich Debian auf meinem zweiten Arbeitsplatz installierte, eine Liste der installierten Software von meinem primären Rechner zu erhalten und sie dann an aptitude weiterzuleiten. Dafür habe ich so etwas gemacht:
dpkg -l | awk ' {print $2} ' > installed
Die meisten Paketmanager bieten heute diese Möglichkeit an, zum Beispiel die -qa-Optionen von rpm, aber die Ausgabe ist mehr, als ich möchte. Ich sehe, dass die zweite Spalte der Ausgabe von dpkg -l den Namen der installierten Pakete enthält, deshalb habe ich $2 mit awk: verwendet, um nur die 2. Spalte zu erhalten.
Grundkonzepte
Wie Sie bemerkt haben, wird die Aktion, die von awk ausgeführt werden soll, in geschweifte Klammern eingeschlossen, und der gesamte Befehl wird in Anführungszeichen gesetzt. Aber die Syntax ist awk 'condition { action }'. In unserem Beispiel hatten wir keine Bedingung, aber wenn wir, sagen wir, nur nach installierten vim-bezogenen Paketen suchen wollten (ja, es gibt grep, aber dies ist ein Beispiel, und warum sollten wir zwei Dienstprogramme verwenden, wenn Sie nur eines verwenden können?), hätten wir dies getan:
dpkg -l | awk ' /'vim'/ {print $2} '
Dieser Befehl würde alle installierten Pakete ausgeben, die "vim" im Namen haben. Eine Sache an awk ist, dass es schnell ist. Wenn Sie "vim" durch "lib" ersetzen, ergibt das auf meinem System 1300 Pakete. Es wird Situationen geben, in denen die Daten, mit denen Sie arbeiten müssen, viel größer sind, und das ist ein Teil, in dem awk glänzt.
Wie auch immer, beginnen wir mit den Beispielen und werden im Folgenden einige Konzepte erklären. Aber vorher wäre es gut zu wissen, dass es mehrere awk-Dialekte und -Implementierungen gibt, und die hier vorgestellten Beispiele befassen sich mit GNU awk als Implementierung und Dialekt. Und aufgrund verschiedener Anführungszeichenprobleme gehen wir davon aus, dass Sie bash, ksh oder sh verwenden, wir unterstützen (t)csh nicht.
Beispiele für AWK-Befehle
Sehen Sie sich einige der folgenden Beispiele an, um ein Verständnis von awk zu erlangen und wie Sie es in Situationen auf Ihrem eigenen System anwenden können. Fühlen Sie sich frei, den Anweisungen zu folgen und einige dieser Befehle in Ihrem Terminal zu verwenden, um die Ausgabe zu sehen, die Sie zurückerhalten.
Drucken Sie nur die Spalten eins und drei mit stdin.
awk ' {print $1,$3} 'Drucken Sie alle Spalten mit stdin.
awk ' {print \$0} 'Drucken Sie nur Elemente aus Spalte 2, die mit dem Muster mit stdin übereinstimmen.
awk ' /'pattern'/ {print $2} '-
Genau wie
makeodersedverwendetawk-f, um seine Anweisungen aus einer Datei zu erhalten, was nützlich ist, wenn es viel zu tun gibt und die Verwendung des Terminals unpraktisch wäre.awk -f script.awk inputfile Führen Sie das Programm mit den Daten aus der Eingabedatei aus.
awk ' program ' inputfileKlassisches "Hallo, Welt" in
awk.awk "BEGIN { print \"Hello, world!!\" }"Gibt aus, was in der Befehlszeile eingegeben wurde, bis EOF (^D).
awk '{ print }'awk-Skriptfür das klassische "Hallo, Welt!" (machen Sie es mitchmodausführbar und führen Sie es so aus, wie es ist).#! /bin/awk -f BEGIN { print "Hello, world!" }Kommentare in
awk-Skripten.This is a program that prints \ "Hello, world!" and exitsDefinieren Sie FS (Feldtrennzeichen) als null, im Gegensatz zu Leerzeichen, dem Standardwert.
awk -F "" 'program' filesFS kann auch ein regulärer Ausdruck sein.
awk -F "regex" 'program' filesWird <'> drucken. Hier ist der Grund, warum wir Bourne-Kessel bevorzugen. 🙂
awk 'BEGIN { print "Here is a single \ quote <'\''>" }'Drucken Sie die Länge der längsten Linie.
awk '{ if (length(\$0) > max) max = \ length(\$0) } END { print max }' inputfile-
Drucken Sie alle Zeilen, die länger als 80 Zeichen sind.
awk 'length(\$0) > 80' inputfile Gibt jede Zeile aus, die mindestens ein Feld enthält (NF steht für Number of Fields).
awk 'NF > 0' dataDrucken Sie sieben Zufallszahlen von 0 bis 100.
awk 'BEGIN { for (i = 1; i <= 7; i++) print int(101 * rand()) }'Gibt die Gesamtzahl der Bytes aus, die von Dateien im aktuellen Verzeichnis verwendet werden.
ls -l . | awk '{ x += $5 } ; END \ { print "total bytes: " x }' total bytes: 7449362Gibt die Gesamtzahl der Kilobyte aus, die von Dateien im aktuellen Verzeichnis verwendet werden.
ls -l . | awk '{ x += $5 } ; END \ { print "total kilobytes: " (x + \ 1023)/1024 }' total kilobytes: 7275.85Drucken Sie eine sortierte Liste der Anmeldenamen.
awk -F: '{ print $1 }' /etc/passwd | sortGibt die Anzahl der Zeilen in einer Datei aus, da NR für Anzahl der Zeilen steht.
awk 'END { print NR }' inputfileDrucken Sie die geraden Zeilen in einer Datei. Wie würden Sie die ungeraden Zeilen drucken?
awk 'NR % 2 == 0' dataGibt die Gesamtzahl der Bytes der Dateien aus, die zuletzt im November geändert wurden.
ls -l | awk '$6 == "Nov" { sum += $5 } END { print sum }'Regulärer Ausdruck, der allen Einträgen im ersten Feld entspricht, die mit einem großen j beginnen.
awk '$1 /J/' inputfileRegulärer Ausdruck, der allen Einträgen im ersten Feld entspricht, die nicht mit einem großen j beginnen.
awk '$1 !/J/' inputfileVermeiden von doppelten Anführungszeichen in
awk.awk 'BEGIN { print "He said \"hi!\" \ to her." }'Druckt "<A>bcd"
echo aaaabcd | awk '{ sub(/a+/, \ "<A>"); print }'Beispiel für die Namensnennung; Versuch es 🙂
ls -lh | awk '{ owner = $3 ; $3 = $3 \ " 0wnz"; print $3 }' | uniqÄndern Sie den Bestand und drucken Sie ihn, mit dem Unterschied, dass der Wert des zweiten Feldes um 10 verringert wird.
awk '{ $2 = $2 - 10; print \$0 }' inventoryAuch wenn Feld sechs nicht im Bestand vorhanden ist, können Sie es erstellen, ihm Werte zuweisen und dann anzeigen.
awk '{ $6 = ($5 + $4 + $3 + $2); print \ $6' inventoryOFS ist das Trennzeichen für das Ausgabefeld und der Befehl gibt "a::c:d" und "4" aus, da Feld zwei zwar ungültig ist, aber immer noch vorhanden ist, sodass es gezählt wird.
echo a b c d | awk '{ OFS = ":"; $2 = "" > print \$0; print NF }'Ein weiteres Beispiel für die Erstellung von Feldern; Wie Sie sehen können, wird das Feld zwischen $4 (vorhanden) und $6 (zu erstellen) ebenfalls erstellt (als $5 mit einem leeren Wert), sodass die Ausgabe "a::c:d::new" "6" ist.
echo a b c d | awk ’{ OFS = ":"; \ $2 = ""; $6 = "new" > print \$0; print NF }’Verwerfen von drei Feldern (letzten), indem die Anzahl der Felder geändert wird.
echo a b c d e f | awk ’\ { print "NF =", NF; > NF = 3; print \$0 }’Dies ist ein regulärer Ausdruck, der das Feldtrennzeichen auf Leerzeichen und nichts anderes setzt (nicht gieriger Musterabgleich).
FS=[ ]Dadurch wird nur "a" gedruckt.
echo ' a b c d ' | awk 'BEGIN { FS = \ "[ \t\n]+" } > { print $2 }'Gibt nur die erste Übereinstimmung von RE (regulärer Ausdruck) aus.
awk -n '/RE/{p;q;}' file.txtSetzt FS auf \\
awk -F\\ '...' inputfiles ...Wenn wir einen Datensatz haben wie:
John Doe
1234 Unknown Ave.
Doeville, MA
Dieses Skript setzt das Feldtrennzeichen auf Zeilenumbruch, damit es problemlos auf Zeilen angewendet werden kann.BEGIN { RS = "" ; FS = "\n" } { print "Name is:", $1 print "Address is:", $2 print "City and State are:", $3 print "" }Bei einer Datei mit zwei Feldern werden die Datensätze wie folgt gedruckt:
"field1:field2Feld3; Feld4
…; ..."
Da ORS, das Trennzeichen für Ausgabedatensätze, auf zwei Zeilenumbrüche gesetzt ist und OFS "; ”awk 'BEGIN { OFS = ";"; ORS = "\n\n" } > { print $1, $2 }' inputfileDadurch werden 17 und 18 ausgegeben, da der Ausgabe-ForMaT so festgelegt ist, dass Gleitkommawerte auf den nächstgelegenen ganzzahligen Wert gerundet werden.
awk 'BEGIN { > OFMT = "%.0f" # print numbers as \ integers (rounds) > print 17.23, 17.54 }'Sie können printf hauptsächlich so verwenden, wie Sie es in C verwenden.
awk 'BEGIN { > msg = "Dont Panic!" > printf "%s\n", msg >} 'Gibt das erste Feld als 10-stellige Zeichenfolge im linksbeinen Blocksatz und $2 normal daneben aus.
awk '{ printf "%-10s %s\n", $1, \ $2 }' inputfileDie Dinge schöner machen.
awk 'BEGIN { print "Name Number" print "---- ------" } { printf "%-10s %s\n", $1, \ $2 }' inputfileEinfaches Beispiel für die Datenextraktion, bei dem das zweite Feld in eine Datei mit dem Namen "phone-list" geschrieben wird.
awk '{ print $2 > "phone-list" }' \ inputfileSchreiben Sie die in $1 enthaltenen Namen in eine Datei, sortieren Sie das Ergebnis und geben Sie es in eine andere Datei aus (Sie können auch mit >> anhängen, wie Sie es in einer Shell tun würden).
awk '{ print $1 > "names.unsorted" command = "sort -r > names.sorted" print $1 | command }’ inputfileWird 9, 11, 17 drucken.
awk 'BEGIN { printf "%d, %d, %d\n", 011, 11, \ 0x11 }'Einfache Suche nach foo oder bar.
if (/foo/ || /bar/) print "Found!"Einfache arithmetische Operationen (die meisten Operatoren ähneln C sehr).
awk '{ sum = $2 + $3 + $4 ; avg = sum / 3 > print $1, avg }' gradesEinfacher, erweiterbarer Taschenrechner.
awk '{ print "The square root of", \ $1, "is", sqrt($1) }' 2 The square root of 2 is 1.41421 7 The square root of 7 is 2.64575Druckt jeden Datensatz zwischen Start und Stopp.
awk '$1 == "start", $1 == "stop"' inputfileBEGIN- und END-Regeln werden genau einmal ausgeführt, vor und nach jeder Datensatzverarbeitung.
awk ' > BEGIN { print "Analysis of \"foo\"" } > /foo/ { ++n } > END { print "\"foo\" appears", n,\ "times." }’ inputfileSuche mit der Shell.
echo -n "Enter search pattern: " read pattern awk "/$pattern/ "'{ nmatches++ } END { print nmatches, "found" }' inputfileEinfache Bedingung.
awkunterstützt wie C auch die ?:-Operatoren.if (x % 2 == 0) print "x is even" else print "x is odd"Druckt die ersten drei Felder jedes Datensatzes, eines pro Zeile.
awk '{ i = 1 while (i <= 3) { print $i i++ } }’ inputfileDruckt die ersten drei Felder jedes Datensatzes, eines pro Zeile.
awk '{ for (i = 1; i <= 3; i++) print \$i }'Wenn Sie das Beenden mit einem anderen Fehlercode als 0 beenden, bedeutet dies, dass etwas nicht ganz in Ordnung ist. Hier ist ein Beispiel.
BEGIN { if (("date" | getline date_now) <= 0) { print "Can't get system date" > \ "/dev/stderr" exit 1 } print "current date is", date_now close("date") }Druckt awk Datei1 Datei2.
awk 'BEGIN { > for (i = 0; i < ARGC; i++) > print ARGV[i] > }’ file1 file2Löschen von Elementen in einem Array.
for (i in frequencies) delete frequencies[i]Überprüfen Sie, ob Array-Elemente vorhanden sind.
foo[4] = "" if (4 in foo) print "This is printed, even though foo[4] \ is empty"Eine
awk-Variantevon ctime() in C. So definieren Sie Ihre eigenen Funktionen inawk.function ctime(ts, format) { format = "%a %b %d %H:%M:%S %Z %Y" if (ts == 0) ts = systime() # use current time as default return strftime(format, ts) }Ein Cliff-Zufallszahlengenerator.
BEGIN { _cliff_seed = 0.1 } function cliff_rand() { _cliff_seed = (100 * log(_cliff_seed)) % 1 if (_cliff_seed < 0) _cliff_seed = - _cliff_seed return _cliff_seed }Anonymisieren Sie ein Apache-Protokoll (IPs werden zufällig ausgewählt).
cat apache-anon-noadmin.log | \ awk 'function ri(n) \ { return int(n*rand()); } \ BEGIN { srand(); } { if (! \ ($1 in randip)) { \ randip[$1] = sprintf("%d.%d.%d.%d", \ ri(255), ri(255)\ , ri(255), ri(255)); } \ $1 = randip[$1]; print \$0 }'
Schlussfolgerung
Wie Sie sehen können, können Sie mit awk viel Textverarbeitung und andere raffinierte Dinge erledigen. Wir sind nicht auf fortgeschrittenere Themen eingegangen, wie z.B. die vordefinierten Funktionen von awk, aber wir haben Ihnen genug gezeigt (hoffentlich), um es als mächtiges Werkzeug in Erinnerung zu behalten.
