Dieser Text bezieht sich nur auf die GNU -Implementierung von awk , die als gawk Witch bekannt ist, die am häufigsten verwendete und verfügt über eine moderne Linux / UNIX -Verteilung.
[Die GNU AWK-Benutzerhandbuch] [GNU-Awk] ist seine Referenz, für die Beispiele , die ich reale Fälle verwendet habe, die hauptsächlich von meinen [Stackoverflow] [so] Antworten entnommen wurden.
Awk ist eine ähnliche Sprache wie Perl, nur wesentlich eleganter.
- Arnold Robbins
AWK ist eine Programmiersprache, die für die Textverarbeitung entwickelt und in der Regel als Datenextraktion und Berichterstattung verwendet wird. Es ist ein Standardmerkmal der meisten Unix-ähnlichen Betriebssysteme.
awk Award Name ...Sein Name leitet sich aus den Nachnamen seiner Autoren ab - Alfred A Ho, Peter W. Einberger und Brian K Ernighan.
awk ...Suchen Sie nach Zeilen, die bestimmte Muster in Dateien oder die Standardeingabe enthalten.
Meistens für die Datenextraktion und -berichterstattung verwendet, wie die Zusammenfassung von Informationen aus der Ausgabe anderer Versorgungsprogramme.
C-like Syntax.
Datenorientiert: Beschreiben Sie die Daten, mit denen Sie arbeiten möchten, und welche Aktion, wenn Sie sie finden.
pattern { action }
pattern { action }Wenn das Programm kurz ist:
awk ' program ' input-file1 input-file2HINWEIS: Achten Sie auf Shell -Zitat von Problemen 1 .
cmd | awk ' program ' HINWEIS: Das pipe leitet die Ausgabe des linken Befehls ( cmd ) in die Eingabe des awk -Befehls 2 weiter.
Wenn der Code lang ist, ist es normalerweise bequemer, ihn in eine Datei zu stecken und ihn mit einem solchen Befehl auszuführen:
awk -f program-file input-file1 input-file2
cmd | awk -f program-file Oder machen Sie es einfach ausführbar wie ein shebang :
#! /bin/awk -f
BEGIN { print " hello world!! " } -F fs setzen die FS -Variable auf fs .
-v var=val setzen die variable var auf den Wert val bevor die Ausführung des Programms beginnt.
HINWEIS : Es kann mehr als einmal verwendet werden und setzt jedes Mal eine andere Variable ein.
Diese speziellen Muster oder Blöcke liefern Start- und Reinigungsaktionen für awk -Programme.
BEGIN{
// initialize variables
}
{
/pattern/ { action }
}
END{
// cleanup
}BEGIN , bevor der erste Eingabeinsatz gelesen wird, END nachdem alle Eingaben verbraucht wurden.
$ echo " hello " | awk ' BEGIN{print "BEGIN";f=1}
{print $f}
END{print "END"} '
BEGIN
hello
ENDgrepping , wenn Sie awk haben? $ cat lorem_ipsum.dat
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
Maecenas pellentesque erat vel tortor consectetur condimentum.
Nunc enim orci, euismod id nisi eget, interdum cursus ex.
Curabitur a dapibus tellus.
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
Aliquam interdum mauris volutpat nisl placerat, et facilisis.$ grep dolor lorem_ipsum.dat
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
Lorem ipsum dolor sit amet, consectetur adipiscing elit.$ awk ' /dolor/ ' lorem_ipsum.dat
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
Lorem ipsum dolor sit amet, consectetur adipiscing elit.HINWEIS: Wenn die Aktion nicht angegeben ist, drucken Sie den Datensatz , der dem angegebenen Muster entspricht.
Aber ... wie können wir das erste und letzte Wort jeder Zeile herausfinden?
Natürlich kann grep , benötigen aber zwei Schritte:
$ grep -Eo ' ^[^ ]+ ' lorem_ipsum.dat
Lorem
Maecenas
Nunc
Curabitur
Lorem
Aliquam$ grep -Eo ' [^ ]+$ ' lorem_ipsum.dat
elit.
condimentum.
ex.
tellus.
elit.
ultrices. Lassen Sie awk hier in Aktion sehen:
$ awk ' {print $1,$NF} ' lorem_ipsum.dat
Lorem elit.
Maecenas condimentum.
Nunc ex.
Curabitur tellus.
Lorem elit.
Aliquam ultrices. awk unterteilt die Eingabe für Ihr Programm in Datensätze und Felder .
Die Datensätze werden durch ein Zeichen getrennt, das den Rekordtrennzeichen Rs namens namens Record Separator RS getrennt ist. Standardmäßig ist das Datensatzabscheider das Unix Newline -Zeichen n .
Aus diesem Grund sind Datensätze standardmäßig einzelne Zeilen .
Zusätzlich hat awk ORS -Ausgangsdatensatzabscheider, um die Art und Weise zu steuern, wie Datensätze dem stdout präsentiert werden.
RS und ORS sollten in Anführungszeichen eingeschlossen sein, die eine Stringkonstante anzeigen.
Um ein anderes Zeichen oder ein Regex zu verwenden, weisen Sie es einfach den RS oder / / und ORS -Variablen zu:
BEGIN , bevor die Eingabe verarbeitet wird, sodass der erste Datensatz mit dem richtigen Trennzeichen gelesen wird.Beispiele:
$ awk ' BEGIN{RS=" *, *";ORS="<<<---n"}
{print $0} ' lorem_ipsum.dat
Lorem ipsum dolor sit amet <<< ---
consectetur adipiscing elit.
Maecenas pellentesque erat vel tortor consectetur condimentum.
Nunc enim orci <<< ---
euismod id nisi eget <<< ---
interdum cursus ex.
Curabitur a dapibus tellus.
Lorem ipsum dolor sit amet <<< ---
consectetur adipiscing elit.
Aliquam interdum mauris volutpat nisl placerat <<< ---
et facilisis neque ultrices.
<<< --- $ awk ' {print $0} ' RS= " *, * " ORS= " <<<---n " lorem_ipsum.dat
Lorem ipsum dolor sit amet <<< ---
consectetur adipiscing elit.
Maecenas pellentesque erat vel tortor consectetur condimentum.
Nunc enim orci <<< ---
euismod id nisi eget <<< ---
interdum cursus ex.
Curabitur a dapibus tellus.
Lorem ipsum dolor sit amet <<< ---
consectetur adipiscing elit.
Aliquam interdum mauris volutpat nisl placerat <<< ---
et facilisis neque ultrices.
<<< --- awk -Datensätze werden automatisch analysiert oder in Brocken als Felder unterteilt.
Standardmäßig werden Felder durch Whitespace (jede Zeichenfolge von einem oder mehreren Leerzeichen, Registerkarten oder neuen Zeilen) wie Wörter in einer Zeile getrennt.
Um sich auf ein Feld in einem awk -Programm zu verweisen, verwenden Sie ein Dollar $ Zeichen, gefolgt von der Anzahl des gewünschten Feldes.
So bezieht sich $1 auf das erste Feld, $2 für das zweite und so weiter.
WICHTIG : $0 repräsentiert den gesamten Eingangsdatensatz.
$ awk ' {print $3} ' lorem_ipsum.dat
dolor
erat
orci,
dapibus
dolor
mauris NF ist eine vordefinierte Variable. Der Wert ist die Anzahl der Felder im aktuellen Datensatz . $NF wird also immer das letzte Feld des Rekords sein.
$ awk ' {print NF} ' lorem_ipsum.dat
8
7
10
4
8
10vs.
$ awk ' {print $NF} ' lorem_ipsum.dat
elit.
condimentum.
ex.
tellus.
elit.
facilisis. FS hält den Wert des Feldseparators , dieser Wert ist eine Single-Charakter-Zeichenfolge oder eine regex , die den Trennungen zwischen Feldern in einem Eingangsdatensatz übereinstimmt.
Der Standardwert lautet " " , eine Zeichenfolge, die aus einem einzelnen Speicherplatz besteht. Als besondere Ausnahme bedeutet dieser Wert, dass jede Sequenz von Räumen , Registerkarten und/oder Newlines ein einzelner Trennzeichen ist.
In der gleichen Weise wie ORS haben wir eine OFS -Variable, um zu verwalten, wie unsere Felder an den Ausgangsstrom gesendet werden.
$ cat /etc/group
nobody: * :-2:
nogroup: * :-1:
wheel: * :0:root
daemon: * :1:root
kmem: * :2:root
sys: * :3:root
tty: * :4:root$ awk ' !/^(_|#)/&&$1=$1 ' FS= " : " OFS= " <-> " /etc/group
nobody < - > * < - > - 2< - >
nogroup < - > * < - > - 1< - >
wheel < - > * < - > 0 < - > root
daemon < - > * < - > 1 < - > root
kmem < - > * < - > 2 < - > root
sys < - > * < - > 3 < - > root
tty < - > * < - > 4 < - > root Hinweis : Ummm ... $1=$1 ???? 3
Unter Berücksichtigung von Aufzeichnungen und Feldern waren jetzt bereit, unseren vorherigen Code zu verstehen:
$ awk ' {print $1,$NF} ' lorem_ipsum.dat
Lorem elit.
Maecenas condimentum.
Nunc ex.
Curabitur tellus.
Lorem elit.
Aliquam ultrices.Dies sind zwei nützliche integrierte Variablen:
NR : Anzahl der Eingabeaufzeichnungen, awk seit Beginn der Ausführung des Programms verarbeitet wurden.
FNR : Die aktuelle Datensatznummer In der aktuellen Datei setzt awk FNR bei jedem Start einer neuen Eingabedatei auf Null zurück.
$ cat n1.dat
one
two$ cat n2.dat
three
four$ awk ' {print NR,FNR,$0} ' n1.dat n2.dat
1 1 one
2 2 two
3 1 three
4 2 fourDie Formatzeichenfolge ist der in der ISO c sehr ähnlich.
Syntax:
printf format, item1, item2, …
$ awk ' {printf "%20s <-> %sn",$1,$NF} ' lorem_ipsum.dat
Lorem < - > elit.
Maecenas < - > condimentum.
Nunc < - > ex.
Curabitur < - > tellus.
Lorem < - > elit.
Aliquam < - > ultrices. Die Ausgabe von print und printf wird standardmäßig in die Standardausgabe gerichtet, können jedoch die Umleitung verwenden, um das Ziel zu ändern.
Umleitungen in awk werden genauso wie Umleitungen in Shell -Befehlen geschrieben, außer dass sie im awk -Programm geschrieben sind.
$ awk ' BEGIN{print "hello">"hello.dat"} ' $ awk ' BEGIN{print "world!">>"hello.dat"} ' $ cat hello.dat
hello
world !Es ist auch möglich, die Ausgabe über ein Rohr an ein anderes Programm zu senden:
$ awk ' BEGIN{sh="/bin/sh";print "date"|sh;close(sh)} '
dom nov 13 18:36:25 CET 2016 Die [Streams] können auf das stdin , den stdout und den stderr hingewiesen werden.
Zum Beispiel können wir wie folgt eine Fehlermeldung an den stderr schreiben:
$ awk ' BEGIN{print "Serious error detected!" > "/dev/stderr"} '
Serious error detected ! In awk sind die Arrays assoziativ , jeder ist eine Sammlung von Paaren , Index - Wert , wobei die beliebige Zahl oder Zeichenfolge ein Index sein kann.
Es ist keine Erklärung erforderlich; Neue Paare können jederzeit hinzugefügt werden.
| Index | Wert |
|---|---|
| "Perro" | "Hund" |
| "Gato" | "Katze" |
| "Uno" | "eins" |
| 1 | "eins" |
| 2 | "zwei" |
Ein Array zu verweisen:
array[index-expression]
Werte zuweisen:
array[index-expression] = value
Um zu überprüfen, ob ein Schlüssel indiziert ist:
indx in array
Um es zu iterieren:
for (var in array) {
var, array[var]
}Verwenden numerischer Werte als Indizes und Erhaltung der Reihenfolge:
for (i = 1 ; i < = max_index ; i++) {
print array[i]
}Ein vollständiges Beispiel:
$ cat dict.dat
uno one
dos two
tres three
cuatro fourawk ' {dict[$1]=$2}
END{if ("uno" in dict)
print "Yes we have uno in dict!"
if (!("cinco" in dict))
print "No , cinco is not in dict!"
for (esp in dict){
print esp, "->" ,dict[esp]
}
} ' dict.datGibt dir:
Yes we have uno in dict !
No , cinco is not in dict !
uno - > one
dos - > two
tres - > three
cuatro - > four gawk sortiert standardmäßig keine Arrays:
awk ' BEGIN{
a[4]="four"
a[1]="one"
a[3]="three"
a[2]="two"
a[0]="zero"
exit
}
END{for (idx in a){
print idx, a[idx]
}
} ' 4 four
0 zero
1 one
2 two
3 threeSie können jedoch [Procinfo] zum Sortieren nutzen:
awk ' BEGIN{
PROCINFO["sorted_in"] = "@ind_num_asc"
a[4]="four"
a[1]="one"
a[3]="three"
a[2]="two"
a[0]="zero"
exit
}
END{for (idx in a){
print idx, a[idx]
}
} ' 0 zero
1 one
2 two
3 three
4 four gensub(regexp, replacement, how [, target]) : ist die fortschrittlichste Funktion für die Zeichenfolge.
Und ihre einfacheren Alternativen:
gsub(regexp, replacement [, target])
sub(regexp, replacement [, target])
Diese Datei haben:
$ cat lorem.dat
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
Maecenas pellentesque erat vel tortor consectetur condimentum.
Nunc enim orci, euismod id nisi eget, interdum cursus ex.
Curabitur a dapibus tellus.
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
Aliquam interdum mauris volutpat nisl placerat, et facilisis.Wir werden die Position der Wörter links und rechts von jedem Komma austauschen.
$ awk ' {print gensub(/([^ ]+)( *, *)([^ ]+)/,
"\3\2\1", "g")} ' lorem.dat
Lorem ipsum dolor sit consectetur, amet adipiscing elit.
Maecenas pellentesque erat vel tortor consectetur condimentum.
Nunc enim euismod, orci id nisi interdum, eget cursus ex.
Curabitur a dapibus tellus.
Lorem ipsum dolor sit consectetur, amet adipiscing elit.
Aliquam interdum mauris volutpat nisl et, placerat facilisis. Mit gensub erfassen wir drei Gruppen und tauschen dann die Bestellung aus.
Um eine einfachere Aktion zu veranschaulichen, ändern wir die Punkte für Kommas :
awk ' $0=gensub(/./, ",", "g") ' lorem.dat
Lorem ipsum dolor sit amet, consectetur adipiscing elit,
Maecenas pellentesque erat vel tortor consectetur condimentum,
Nunc enim orci, euismod id nisi eget, interdum cursus ex,
Curabitur a dapibus tellus,
Lorem ipsum dolor sit amet, consectetur adipiscing elit,
Aliquam interdum mauris volutpat nisl placerat, et facilisis, Verwenden von gsub -Alternative:
awk ' gsub(/./, ",") ' lorem.dat
Lorem ipsum dolor sit amet, consectetur adipiscing elit,
Maecenas pellentesque erat vel tortor consectetur condimentum,
Nunc enim orci, euismod id nisi eget, interdum cursus ex,
Curabitur a dapibus tellus,
Lorem ipsum dolor sit amet, consectetur adipiscing elit,
Aliquam interdum mauris volutpat nisl placerat, et facilisis,Diese Option scheint besser zu sein, wenn keine Gruppenerfassung erforderlich ist.
Andere interessante Funktionen sind index und substr .
index(in, find)
substr(string, start [, length ])
Funktioniert so:
$ awk ' BEGIN{t="hello-world";print index(t, "-")} '
6$ awk ' BEGIN{t="hello-world";print substr(t,index(t, "-")+1)} '
world Die split -Funktion wird verwendet, um ein Array aus einer Zeichenfolge zu erstellen, die es durch ein Separator -Zeichen dividiert. Es gibt die Anzahl der Elemente des erstellten Arrays zurück.
split(string, array [, fieldsep [, seps ] ])
$ cat passwd
jd001:x:1032:666:Javier Diaz:/home/jd001:/bin/rbash
ag002:x:8050:668:Alejandro Gonzalez:/home/ag002:/bin/rbash
jp003:x:1000:666:Jose Perez:/home/jp003:/bin/bash
ms004:x:8051:668:Maria Saenz:/home/ms004:/bin/rbash
rc005:x:6550:668:Rosa Camacho:/home/rc005:/bin/rbash$ awk ' n=split($0, a, ":"){print n, a[n]} ' passwd
7 /bin/rbash
7 /bin/rbash
7 /bin/bash
7 /bin/rbash
7 /bin/rbashHinweis : Dies könnte auf viel einfachere Weise geschehen:
$ awk ' {print NF,$NF} ' FS= ' : ' passwd
7 /bin/rbash
7 /bin/rbash
7 /bin/bash
7 /bin/rbash
7 /bin/rbashSchreiben Sie eine benutzerdefinierte Funktion ist recht einfach:
awk ' function test(m)
{
printf "This is a test func, parameter: %sn", m
}
BEGIN{test("param")} 'Gib uns:
This is a test func, parameter: param Wir können auch einen Ausdruck mit einer return -Anweisung zurückgeben:
awk ' function test(m)
{
return sprintf("This is a test func, parameter: %s", m)
}
BEGIN{print test("param")} 'Das Parsen nach Parameter ist die einzige Möglichkeit, eine lokale Variable innerhalb einer Funktion zu erstellen.
Skalarwerte werden nach Wert und Arrays durch Bezugnahme übergeben. Daher spiegelt sich jede Änderung an einem Array innerhalb einer Funktion im globalen Bereich wider:
awk ' function test(m)
{
m[0] = "new"
}
BEGIN{m[0]=1
test(m)
exit
}
END{print m[0]} 'Ausgänge:
newUnsere Herausforderungen :
01. Vorletzter Wort eines Datensatzes.
02. Ersetzen eines Datensatzes.
03. Platzieren Sie ein Semikolon am Ende jedes Datensatzes.
04. Platzieren Sie ein Komma zwischen jedem Wort.
05. Alles zusammen?
06. Umleiten von ungeraden Datensätzen in eine Datei und sogar in eine andere.
07. Bei einer Passwortdatei das fehlende Feld erhalten.
08. Fieldwapping.
09. Traceroute Hacking.
10. Wo sind meine Kinder?
11. Datenaggregation.
12. Aufzeichnungen zwischen zwei Mustern.
13. Feldtransformation.
14. Datensätze zu Spalten.
15. Fasta -Dateiverarbeitung.
16. Komplexe Berichterstattung.
17. Dateien Joiner.
18. Passwd und Gruppe.
19. Benutzerverbindungen.
20. Laufzeit Gesamtlastdurchschnitt.
Diese Quelldatei haben:
$ cat lorem.dat
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
Maecenas pellentesque erat vel tortor consectetur condimentum.
Nunc enim orci, euismod id nisi eget, interdum cursus ex.
Curabitur a dapibus tellus.
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
Aliquam interdum mauris volutpat nisl placerat, et facilisis.$ awk ' {print $(NF-1)} ' lorem.dat
adipiscing
consectetur
cursus
dapibus
adipiscing
neque NF nicht zu viel zu erklären, speichert die Anzahl der Felder im aktuellen Datensatz, sodass NF-1 auf das Feld vorletzt und $(NF-1) sein Wert sein wird.
Unsere Aufgabe, Datei -Rekord -Substitution, die dritte Zeile muss werden:
This not latin
Nichts einfacheres, einfach um NR herumspielen ( Anzahl der Aufzeichnungen ).
Code:
$ awk ' NR==3{print "This is not latin";next}{print} ' lorem.dat
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
Maecenas pellentesque erat vel tortor consectetur condimentum.
This is not latin
Curabitur a dapibus tellus.
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
Aliquam interdum mauris volutpat nisl placerat, et facilisis. Alternative Lösung, um next Anweisung zu vermeiden: Weisen Sie die neue Zeile dem vollständigen Datensatz $0 zu.
Beispiel:
$ awk ' NR==3{$0="This is not latin"}1 ' lorem.dat
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
Maecenas pellentesque erat vel tortor consectetur condimentum.
This is not latin
Curabitur a dapibus tellus.
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
Aliquam interdum mauris volutpat nisl placerat, et facilisis.$ awk ' 1 ' ORS= " ;n " lorem.dat
Lorem ipsum dolor sit amet, consectetur adipiscing elit. ;
Maecenas pellentesque erat vel tortor consectetur condimentum. ;
Nunc enim orci, euismod id nisi eget, interdum cursus ex. ;
Curabitur a dapibus tellus. ;
Lorem ipsum dolor sit amet, consectetur adipiscing elit. ;
Aliquam interdum mauris volutpat nisl placerat, et facilisis neque ultrices. ; Da der Standard RS die UNIX -Break -Zeile n ist, müssen wir das Semikolon nur zum Ausgangsrekordtrenntrennzeichen von OFS präfixen .
1 ? 4
$ awk ' {$1=$1}1 ' OFS= ' , ' lorem.dat
Lorem,ipsum,dolor,sit,amet,,consectetur,adipiscing,elit.
Maecenas,pellentesque,erat,vel,tortor,consectetur,condimentum.
Nunc,enim,orci,,euismod,id,nisi,eget,,interdum,cursus,ex.
Curabitur,a,dapibus,tellus.
Lorem,ipsum,dolor,sit,amet,,consectetur,adipiscing,elit.
Aliquam,interdum,mauris,volutpat,nisl,placerat,,et,facilisis,neque,ultrices. Der wichtigste Teil dieses Kodex ist, wie ein Rekordrekonstruktion mit $1=$1 für den aktuellen Wert der OFS erzwungen wird.
$ awk ' {$1=$1}1 ' OFS= ' , ' ORS= ' ;n ' lorem.dat
Lorem,ipsum,dolor,sit,amet,,consectetur,adipiscing,elit. ;
Maecenas,pellentesque,erat,vel,tortor,consectetur,condimentum. ;
Nunc,enim,orci,,euismod,id,nisi,eget,,interdum,cursus,ex. ;
Curabitur,a,dapibus,tellus. ;
Lorem,ipsum,dolor,sit,amet,,consectetur,adipiscing,elit. ;
Aliquam,interdum,mauris,volutpat,nisl,placerat,,et,facilisis,neque,ultrices. ; Als einfach als Spiel mit Ausgangsvars: OFS und ORS .
Beginnen wir mit der endgültigen Lösung:
$ awk ' NR%2{print > "even.dat";next}
{print > "odd.dat"} ' lorem.dat$ cat even.dat
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
Nunc enim orci, euismod id nisi eget, interdum cursus ex.
Lorem ipsum dolor sit amet, consectetur adipiscing elit$ cat odd.dat
Maecenas pellentesque erat vel tortor consectetur condimentum.
Curabitur a dapibus tellus.
Aliquam interdum mauris volutpat nisl placerat, et facilisis. Die [Modulo] -Funktion ( % ) findet den Rest nach der Aufteilung für die aktuelle Datensatznummer NR geteilt durch zwei:
$ awk ' {print NR%2} ' lorem.dat
1
0
1
0
1
0 Soweit wir noch jetzt sind, ist in awk 1 wahr und 0 falsch . Wir leiten unsere Ausgabe um, die diese Tatsache bewertet.
next erfordert es eine besondere Aufmerksamkeit. Es zwingt awk , den aktuellen Rekordvorgang sofort zu stoppen und an die nächste zu gelangen.
Auf diese Weise entziehen wir uns einem doppelten Zustand, der so aussehen würde:
awk ' NR % 2{print > "even.dat"}
!NR % 2{print > "odd.dat"} ' lorem.dat$ cat /etc/passwd
jd001:x:1032:666:Javier Diaz::/bin/rbash
ag002:x:8050:668:Alejandro Gonzalez::/bin/rbash
jp003:x:1000:666:Jose Perez::/bin/bash
ms004:x:8051:668:Maria Saenz::/bin/rbash
rc005:x:6550:668:Rosa Camacho::/bin/rbash Nehmen wir das Home -Verzeichnis an, indem wir die feste Zeichenfolge "/home/" dem Benutzernamen vorangestellt:
$ awk ' $6="/home/"$1 ' FS= ' : ' OFS= ' : ' /etc/passwd
jd001:x:1032:666:Javier Diaz:/home/jd001:/bin/rbash
ag002:x:8050:668:Alejandro Gonzalez:/home/ag002:/bin/rbash
jp003:x:1000:666:Jose Perez:/home/jp003:/bin/bash
ms004:x:8051:668:Maria Saenz:/home/ms004:/bin/rbash
rc005:x:6550:668:Rosa Camacho:/home/rc005:/bin/rbashUnser erster Schritt sollte darin bestehen, den Feldabscheider, einen Dickdarm, sowohl für die Eingabe als auch für die Ausgabe zu berücksichtigen.
Dann müssen wir die Leerfeldposition finden, 6 für dieses Beispiel.
Schließlich komponieren wir den erforderlichen Wert mit der angegebenen Zeichenfolge und dem im ersten Feld gespeicherten Benutzeranmeldung.
print sind nicht erforderlich, da der Rückgabewert $6 -Dollar immer wahr ist, und die Standardaktion awk ist das Drucken des betroffenen Datensatzes.
Unser Ziel: Das letzte Feld sollte zuerst und zum ersten Mal zuletzt werden.
Endgültiger Code:
$ awk -F : ' {last=$1;$1=$NF;$NF=last}1 ' FS= " : " OFS= ' : ' /etc/passwd
/bin/rbash:x:1032:666:Javier Diaz:/home/jd001:jd001
/bin/rbash:x:8050:668:Alejandro Gonzalez:/home/ag002:ag002
/bin/bash:x:1000:666:Jose Perez:/home/jp003:jp003
/bin/rbash:x:8051:668:Maria Saenz:/home/ms004:ms004
/bin/rbash:x:6550:668:Rosa Camacho:/home/rc005:rc005 Wir spielen mit einer Zwischenvariable , die verwendet wird, um den ersten Feldwert zu speichern. Der WIR VERWEISEN SIE SEINEN Wert mit dem letzten, schließlich weisen wir $NF ( $NF=last ) last Variable zu.
Diese Ausgabe haben:
$ traceroute -q 1 google.com 2> /dev/null
1 hitronhub.home (192.168.1.1) 5.578 ms
2 217.217.0.1.dyn.user.ono.com (217.217.0.1) 9.732 ms
3 10.127.54.181 (10.127.54.181) 10.198 ms
4 62.42.228.62.static.user.ono.com (62.42.228.62) 35.519 ms
5 72.14.235.20 (72.14.235.20) 26.003 ms
6 216.239.50.133 (216.239.50.133) 25.678 ms
7 mad01s24-in-f14.1e100.net (216.58.211.238) 25.019 msWir müssen die Gesamtzeit des Pakets berechnen.
$ traceroute -q 1 google.com 2> /dev/null |
awk ' {total+=$(NF-1)}
END{print "Total ms: "total} '
Total ms: 153.424Da keine Bedingung angegeben wird, wird die Aktion für alle Datensätze ausgeführt.
total+=$(NF-1) : total wird verwendet, um den Wert jedes Datensatzes vorletzten Feld $(NF-1) zu sammeln .
Schließlich verwenden wir die END , um den endgültigen total anzuzeigen.
Unser Job: Holen Sie sich unsere shell -abhängigen Prozesse.
$ echo $$
51026Erstes : Starten Sie die Hintergrundprozesse.
$ sleep 10 & sleep 15 & sleep 20 &
[1] 86751
[2] 86752
[3] 86753 Mit ps -Dienstprogramm sucht awk nach dem dritten Feld, das als PPID bekannt ist.
HINWEIS : Wir verwenden -v , um PPID VAR vor dem Beginn des Programms einzustellen.
$ ps -ef | awk -v ppid= $$ ' $3==ppid '
501 86751 51026 0 7:57PM ttys001 0:00.00 sleep 10
501 86752 51026 0 7:57PM ttys001 0:00.00 sleep 15
501 86753 51026 0 7:57PM ttys001 0:00.00 sleep 20
0 86754 51026 0 7:57PM ttys001 0:00.00 ps -ef
501 86755 51026 0 7:57PM ttys001 0:00.00 awk $3 ==51026Wir brauchen nur den Schlaf :
$ ps -ef | awk -v ppid= $$ ' $3 == ppid && /slee[p]/
{print $2" -> "$5} '
86751 - > 7:57PM
86752 - > 7:57PM
86753 - > 7:57PM Die Lösung benötigt einen neuen Zustand, um hinzuzufügen: Finden Sie das Schlafmuster in unserem aktuellen Datensatz /slee[p]/ .
Die ausgelöste Aktion besteht darin, das zweite Feld $2 mit Beständen für die PID und den fünften $5 , den Zeitstempel , zu drucken.
Diese Datei haben:
$ cat ips.dat
IP BYTES
81.220.49.127 328
81.220.49.127 328
81.220.49.127 329
81.220.49.127 367
81.220.49.127 5302
81.226.10.238 328
81.227.128.93 84700 Unsere Aufgabe ist es, zu berechnen, wie viele Bytes pro IP verarbeitet werden.
$ awk ' NR>1{ips[$1]+=$2}
END{for (ip in ips){print ip, ips[ip]}} ' ips.dat
81.220.49.127 6654
81.227.128.93 84700
81.226.10.238 328Haufen von Dingen hier zu erklären.
NR>1{ips[$1]+=$2} : Die Aktion ips[$1]+=$2 wird nur ausgeführt, wenn die aktuelle Datensatznummer größer als ein NR>1 ist. Dies ist erforderlich, um den Header zu vermeiden.
ips ist ein Array, das vom IP -Wert (das Feld $1 ) indiziert wird, für jeden Schlüssel, den wir im Wert des zweiten Feldes ansammeln.
Beachten Sie eine wichtige Tatsache , wenn ein Schlüssel im Array nicht vorhanden ist , fügt awk der Struktur ein neues Element hinzu, andernfalls wird der vorherige Wert aktualisiert, der auf diesen Schlüssel verweist (wie in unserem Beispiel).
Die END wird nur verwendet , um das Array nach Indizes und Werten zu iterieren.
Dieser Code könnte auf völlig unterschiedliche Weise umgeschrieben werden, um die Verwendung von Arrays zu vermeiden und die Reihenfolge zu erhalten, die die sortierte IPS -Datei ausgenutzt hat:
awk ' NR==1{next}
lip && lip != $1{print lip,sum;sum=0}
{sum+=$2;lip=$1}
END{print lip,sum} ' ips.dat
81.220.49.127 6654
81.226.10.238 328
81.227.128.93 84700 NR==1{next} : BYPASS DER HEADELL.
lip && lip != $1{print lip,sum;sum=0} : Hier verwenden wir eine var namens lip ( last-ip ). lip && lip != $1 Wenn lip nicht null ist und der Wert nicht gleich dem ersten Feld (das die aktuelle IP enthält) Die ausgelöste Aktion besteht darin, lip zu drucken und die Gesamtmenge der Bytes für die letzte IP sum . Dann initialisieren wir es sum=0 .
Der Trick ist klar, jedes Mal, wenn IP ( $1 ) ändert, zeigen wir die Statistiken der vorherigen.
{sum+=$2;lip=$1} sum+=$2 lip lip=$1 Es ist der letzte Schritt unserer Datensatzverarbeitung.
Der END wird verwendet, um die anstehenden Werte zu drucken.
Dieser Code bewahrt die Reihenfolge, aber meiner Meinung nach geht dies auf Kosten einer erheblich erhöhten Komplexität.
Unsere Aufgabe besteht darin, zwei Zeilen zwischen und OUTPUT und END zu extrahieren.
$ cat pat.dat
test -3
test -2
test -1
OUTPUT
top 2
bottom 1
left 0
right 0
page 66
END
test 1
test 2
test 3 Dies ist ein klassisches Beispiel , mit dem veranschaulicht wird, wie das Muster -Matching in awk und in seinen assoziierten Aktionen funktioniert, die ich für einen vollständigen [Beitrag] gewidmet habe.
$ awk ' /END/{flag=0}flag;/OUTPUT/{flag=1} ' pat.dat
top 2
bottom 1
left 0
right 0
page 66 Es basiert auf dem Variablenwert flag -Variablen. Es ist wahr ( 1 ), wenn der OUTPUT gefunden und falsch ( 0 ) ist, wenn das END erreicht ist.
Um einen zusätzlichen Schritt zu vermeiden, ist die Aktionsreihenfolge sehr wichtig , wenn wir der Logiksequenz folgen:
$ awk ' /OUTPUT/{flag=1}flag;/END/{flag=0} ' pat.dat
OUTPUT
top 2
bottom 1
left 0
right 0
page 66
ENDMuster -Tags werden durch die Ausgabe angezeigt.
Der Grund: Nachdem OUTPUT gefunden wurde, wird das Flag aktiviert, da die nächste Aktion von diesem Flag hängt, wird der Datensatz gedruckt.
Wir können dieses Verhalten vermeiden , die die Flag -Aktivierung als den letzten Schritt des Flusses zu platzieren.
Nehmen wir diese Datei an:
$ cat space.dat
10.80 kb
60.08 kb
35.40 kb
2.20 MB
1.10 MB
40.80 kb
3.15 MB
20.50 kbUnsere Aufgabe wird es sein, unsere Aufzeichnungen des Gesamtgewichts in Mega -Bytes zu berechnen:
$ awk ' {total+= $1 / ($2=="kb" ? 1024: 1)}
END{print total} ' space.dat
6.61365Um zu verstehen, wie es funktioniert, muss ein Konzept klar sein, der [ternäre] Operator (Gegenstand eines alten Beitrags).
total wird verwendet, um die Teilung des ersten Feldes $1 bis zu den zweiten $2 zu sammeln , die den vom ternären Operator angegebenen Wert halten: 1024 , wenn $2 gleich kb und 1 sind, wenn keine Transformation erforderlich ist.
Schließlich drucken wir total im END .
Originalquelle:
$ cat group.dat
string1
string2
string3
string4
string5
string6
string8Unsere Mission ist es, Aufzeichnungen in Blöcken von drei Spalten wie diesem zu gruppieren:
string1 string2 string3
string4 string5 string6
string8 Es mag komplex erscheinen, wird aber viel einfacher, wenn wir verstehen, wie man den Ausgangsfeldabscheider verwendet OFS
$ awk ' ORS = NR%3 ? FS : RS; END{print "n"} ' group.dat
string1 string2 string3
string4 string5 string6
string8 Wenn wir das ORS auf ein leeres Zeichen, den FS -Standardwert, einstellen, wird die gesamte Ausgabe zu einer einzelnen Zeile:
$ awk ' ORS=FS; END{print "n"} ' group.dat
string1 string2 string3 string4 string5 string6 string7 ORS = NR%3 ? FS : RS : Schließlich verwenden wir den ternären Operator (kurz zuvor erklärt), um das Ergebnis der [Modulo] NR%3 Ergebnis der Aufteilung der aktuellen Feldzahl NR um drei zu bewerten.
Wenn der Rest wahr ist, wird der ORS zu FS , ein leerer Speicherplatz, andernfalls wird der RS -Standardwert zugewiesen, der UNIX -Zeilenumbruch n .
In Bioinformatik ist [Fasta] ein textbasiertes Dateiformat.
Das folgende Beispiel haben:
$ cat fasta.dat
> header1
CGCTCTCTCCATCTCTCTACCCTCTCCCTCTCTCTCGGATAGCTAGCTCTTCTTCCTCCT
TCCTCCGTTTGGATCAGACGAGAGGGTATGTAGTGGTGCACCACGAGTTGGTGAAGC
> header2
GGT
> header3
TTATGATWir brauchen die Gesamtlänge jeder Sequenz und einen endgültigen Lebenslauf .
Sollte so aussehen:
> header1
117
> header2
3
> header3
7
3 sequences, total length 127 awk ist das perfekte Werkzeug für diese Berichterstattung . Für dieses Beispiel werden wir verwenden:
awk ' /^>/ { if (seqlen) {
print seqlen
}
print
seqtotal+=seqlen
seqlen=0
seq+=1
next
}
{
seqlen += length($0)
}
END{print seqlen
print seq" sequences, total length " seqtotal+seqlen
} ' fasta.dat
Die erste Aktion ist an die Header -Erkennung gebunden /^>/ , das liegt daran, dass alle Header mit > Charakter Sterne.
Wenn seqlen nicht seinen Wert null ist, der die vorherige Sequenzlänge hält, wird auf das an den neue Header angeschlossene Stdout gedruckt. seqtotal wird aktualisiert und seqlen initialisiert, um die nächste Sequenz zu dienen. Schließlich brechen wir die weitere Aufzeichnungsverarbeitung mit next ab.
Die zweite Aktion {seqlen += length($0)} wird verwendet, um seqlen zu aktualisieren, um die Gesamtdatensatzlänge zu summieren.
Der Zweck der Endregel END darin, die unbedruckte Sequenz und die Gesamtsummen zu zeigen.
Trick hier besteht darin, die vorherige Sequenzlänge zu drucken, wenn wir einen neuen Header gefunden haben.
Wenn wir den ersten Datensatz verarbeiten, hat seqlen keinen Wert, also überspringen wir die Visualisierung.
Quelle:
$ cat report.dat
snaps1: Counter: 4966
Opens: Counter: 357283
Instance: s.1.aps.userDatabase.mount275668.attributes
snaps1: Counter: 0
Opens: Counter: 357283
Instance: s.1.aps.userDatabase.test.attributes
snaps1: Counter: 5660
Opens: Counter: 37283
Instance: s.1.aps.userDatabase.mount275000.attributes Unsere Pflicht : Erstellen Sie einen Bericht , um snaps und instance zu visualisieren, aber nur, wenn das erste Zähler -Tag von SNAP größer als Null ist .
Erwartete Ausgabe:
snaps1: Counter: 4966
Instance: s.1.aps.userDatabase.mount275668.attributes
snaps1: Counter: 5660
Instance: s.1.aps.userDatabase.mount275000.attributesWir spielen wieder mit Mustern und Flaggen : Flaggen:
awk ' {$1=$1}
/snaps1/ && $NF>0{print;f=1}
f && /Instance/ {print;f=0} ' report.dat Für jeden Datensatz wird die erste Aktion ausgeführt . Sie zwingt awk , den gesamten Datensatz wieder aufzubauen , wobei die aktuellen Werte für OFS 3 verwendet werden.
Dieser Trick ermöglicht es uns, einen Multiple -Space -Separator in ein einzelnes Zeichen zu konvertieren, den Standardwert für den Ausgangsfeldtrennzeichen.
Mal sehen:
$ awk ' 1 ' text.dat
one two
three four$ awk ' $1=$1 ' text.dat
one two
three four Die zweite Aktion wird ausgelöst , wenn das Muster gefunden wird und das letzte Feld größer als Null /snaps1/ && $NF>0 .
awk druckt den Datensatz und weisen dem Flag -Druck einen echten Wert zu print;f=1 .
Letzter Schritt: Wenn die Flagge wahr ist und Instanzmuster in der Zeile f && /Instance/ , zeigen Sie die Zeile und deaktiviertes Flag: print;f=0 .
Nehmen wir zwei Archive an:
$ cat join1.dat
3.5 22
5. 23
4.2 42
4.5 44$ cat join2.dat
3.5
3.7
5.
6.5 Wir brauchen die Datensätze von der ersten join1.dat , wenn die ersten Felder im zweiten join2.dat sind.
Ausgabe sollte sein:
3.5 22
5. 23Natürlich können wir Unix Join Utility verwenden, aber wir müssen die erste Datei sortieren:
$ join <( sort join1.dat ) join2.dat
3.5 22
5. 23 Nicht benötigt in awk :
$ awk ' NR == FNR{a[$1];next}
$1 in a ' join2.dat join1.datLassen Sie uns die Filter und Handlungen untersuchen:
NR == FNR : Datensatznummer, die der Datensatzdateinummer entspricht, bedeutet, dass wir die erste an awk analyse: join2.dat .
Die Paaraktion a[$1];next wird es sein, dem vom ersten Feld indizierten Array einen neuen Hohlwert zu verleihen. next Anweisung wird die Datensatzverarbeitung durchbrechen und den Fluss an den nächsten übergeben.
Für die zweite Aktion wird NR != FNR implizit angewendet und nur auf join1.dat auswirkt. Die zweite Bedingung beträgt $1 in a , das zutrifft , wenn das erste Feld von join1.dat ein Array -Schlüssel ist.
Diese sind zu Unix -Klassikern :
$ cat /etc/group
dba:x:001:
netadmin:x:002:$ cat /etc/passwd
jd001:x:1032:001:Javier Diaz:/home/jd001:/bin/rbash
ag002:x:8050:002:Alejandro Gonzalez:/home/ag002:/bin/rbash
jp003:x:1000:001:Jose Perez:/home/jp003:/bin/bash
ms004:x:8051:002:Maria Saenz:/home/ms004:/bin/rbash
rc005:x:6550:002:Rosa Camacho:/home/rc005:/bin/rbashUnser Ziel, ein Bericht wie diesen:
d001:dba
ag002:netadmin
jp003:dba
ms004:netadmin
rc005:netadminWir brauchen einen mehrfachen Dateifluss , wie wir in unserem letzten Beispiel untersucht haben:
$ awk -F : ' NR == FNR{g[$3]=$1;next}
$4 in g{print $1""FS""g[$4]} ' /etc/group /etc/passwd Um zu verarbeiten /etc/group wiederholen wir den NR == FNR -Vergleich und speichern dann den Namen der Gruppe $1 indexiert durch seine ID $3 : g[$3]=$1 . Schließlich brechen wir die weitere Aufzeichnungsverarbeitung mit next ab.
Die zweite Bedingung richtet sich nur an /etc/passwd -Datensätze. Wenn das vierte Feld $4 ( Gruppen -ID ) im Array $4 in g vorhanden ist, drucken wir das Anmeldung und der Wert, der vom Array gezeigt wird , das von der Gruppen -ID g[$4] gezeigt wird, also: print $1""FS""g[$4] .
Beispiel für Benutzer von Benutzern: Beispiel: Beispiel:
$ users
negan rick bart klashxx klashxx ironman ironman ironmanWir werden Anmeldungen pro Benutzer zählen .
$ users | awk ' {a[$1]++}
END{for (i in a){print i,a[i]}} ' RS= ' + '
rick 1
bart 1
ironman 3
negan 1
klashxx 2Die Aktion wird für alle Datensätze ausgeführt.
a[$1]++ : Dies ist der Zähler , für jeden Benutzer erhöht es den $1 Wert (nicht initialisierte Vars haben den numerischen Wert Null).
Im END iterieren Sie das Array nach Schlüssel und den gespeicherten Wert , um die Ergebnisse zu präsentieren.
Eine typische Ausgabe:
$ uptime
11:08:51 up 121 days, 13:09, 10 users, load average: 9.12, 14.85, 20.84Wie können wir den Gesamtlastdurchschnitt erhalten?
$ uptime | awk ' {printf "Load average mean: %0.2fn",
($(NF-2)+$(NF-1)+$(NF))/3 } ' FS= ' (:|,) + '
Load average mean: 14.94Hier ist eine neue Technik.
Wir verwenden einen [Regex] als Feldabscheider (:|,) + , sodass der FS ein Dickdarm und ein Komma sein kann, gefolgt von null oder mehr leeren Leerzeichen.
Wir brauchen nur die letzten drei Felder, um die erforderliche Arithmetik auszuführen, und dann verwenden wir printf die an eine ordnungsgemäße Maske angeschlossen sind.
Wenn Sie noch hier sind, danke !!
Aus meiner Sicht ist awk eine unterschätzte Sprache und braucht viel Liebe ❤️.
Wenn Sie nach mehr Hunger sind, lassen Sie mich es im Kommentarbereich brüll wissen und ich werde einen zweiten Teil in Betracht ziehen, um meine Mission zu beenden ... Tragen Sie Sie zu Tode.
Happy Coding!
[Eine Anleitung zur Unix-Shell-Zitat] [Zitierungsguide]. ↩
[Wikipedia auf Pipelines] [Pipes]. ↩
Es gibt Zeiten, in denen es bequem ist, awk zu zwingen, den gesamten Datensatz wiederherzustellen, wobei die aktuellen Werte der FS und OFS verwendet werden.
Dazu verwenden wir die scheinbar harmlose Aufgabe: $1 = $1 ↩ ↩ 2
Schnelle Antwort, es ist nur eine Abkürzung , um die Verwendung der Druckanweisung zu vermeiden.
In awk , wenn eine Bedingung übereinstimmt, besteht die Standardaktion, die Eingabestelle zu drucken.
$ echo "test" |awk '1'
Entspricht:
echo "test"|awk '1==1'
echo "test"|awk '{if (1==1){print}}'
Das liegt daran, dass 1 immer [wahr] sein wird. ↩