GNU/Linux >> LINUX-Kenntnisse >  >> Linux

Erste Schritte mit AWK Command [Leitfaden für Anfänger]

Der AWK-Befehl stammt noch aus den frühen Unix-Tagen. Es ist Teil des POSIX-Standards und sollte auf jedem Unix-ähnlichen System verfügbar sein. Und darüber hinaus.

Obwohl AWK manchmal aufgrund seines Alters oder fehlender Funktionen im Vergleich zu einer Mehrzwecksprache wie Perl diskreditiert wird, bleibt es ein Werkzeug, das ich gerne in meiner täglichen Arbeit verwende. Manchmal zum Schreiben relativ komplexer Programme, aber auch wegen der mächtigen Einzeiler, die Sie schreiben können, um Probleme mit Ihren Datendateien zu lösen.

Genau darum geht es in diesem Artikel. In weniger als 80 Zeichen wird Ihnen gezeigt, wie Sie die AWK-Leistung nutzen können, um nützliche Aufgaben auszuführen. Dieser Artikel soll kein vollständiges AWK-Tutorial sein, aber ich habe dennoch einige grundlegende Befehle zu Beginn hinzugefügt, sodass Sie die Kernkonzepte von AWK erfassen können, selbst wenn Sie wenig oder gar keine Vorkenntnisse haben.

Meine Beispieldateien für dieses AWK-Tutorial

Alle in diesem Artikel beschriebenen Einzeiler werden mit derselben Datendatei getestet:

cat file
CREDITS,EXPDATE,USER,GROUPS
99,01 jun 2018,sylvain,team:::admin
52,01    dec   2018,sonia,team
52,01    dec   2018,sonia,team
25,01    jan   2019,sonia,team
10,01 jan 2019,sylvain,team:::admin
8,12    jun   2018,öle,team:support



17,05 apr 2019,abhishek,guest

Eine Kopie dieser Datei erhalten Sie online auf GitHub.

Vordefinierte und automatische Variablen in AWK kennen

AWK unterstützt einige vordefinierte und automatische Variablen um Ihnen beim Schreiben Ihrer Programme zu helfen. Darunter werden Sie häufig begegnen:

RSDas Datensatztrennzeichen. AWK verarbeitet Ihre Daten Datensatz für Datensatz. Das Datensatztrennzeichen ist das Trennzeichen, das verwendet wird, um den Eingabedatenstrom in Datensätze aufzuteilen. Standardmäßig ist dies das Zeilenumbruchzeichen. Wenn Sie es also nicht ändern, ist ein Datensatz eine Zeile der Eingabedatei.

NRDie aktuelle Eingangsdatensatznummer. Wenn Sie das standardmäßige Zeilenumbruchtrennzeichen für Ihre Datensätze verwenden, entspricht dies der aktuellen Eingabezeilennummer.

FS/OFSDie als Feldtrennzeichen verwendeten Zeichen. Sobald AWK einen Datensatz liest, teilt es ihn basierend auf dem Wert von FS in verschiedene Felder auf . Wenn AWK einen Datensatz auf der Ausgabe ausgibt, werden die Felder wieder zusammengefügt, diesmal jedoch unter Verwendung des OFS Trennzeichen anstelle des FS Separator. Normalerweise FS und OFS sind gleich, müssen aber nicht. „white space“ ist der Standardwert für beide.

NF – Die Anzahl der Felder im aktuellen Datensatz. Wenn Sie für Ihre Felder das standardmäßige „Leerzeichen“-Trennzeichen verwenden, stimmt dieses mit der Anzahl der Wörter im aktuellen Datensatz überein.

Es sind andere mehr oder weniger standardmäßige AWK-Variablen verfügbar, daher lohnt es sich, in Ihrem speziellen AWK-Implementierungshandbuch nach weiteren Details zu suchen. Diese Teilmenge reicht jedoch bereits aus, um interessante Einzeiler zu schreiben.

A. Grundlegende Verwendung des AWK-Befehls

1. Alle Zeilen drucken

Dieses Beispiel ist größtenteils nutzlos, aber es wird dennoch eine gute Einführung in die AWK-Syntax sein:

awk '1 { print }' file
CREDITS,EXPDATE,USER,GROUPS
99,01 jun 2018,sylvain,team:::admin
52,01    dec   2018,sonia,team
52,01    dec   2018,sonia,team
25,01    jan   2019,sonia,team
10,01 jan 2019,sylvain,team:::admin
8,12    jun   2018,öle,team:support



17,05 apr 2019,abhishek,guest

AWK-Programme bestehen aus einem oder mehreren pattern { action } Aussagen.

Wenn für einen bestimmten Datensatz („Zeile“) der Eingabedatei, das Muster einen Wert ungleich Null auswertet (äquivalent zu „true“ in AWK), die Befehle im entsprechenden Aktionsblock werden hingerichtet. Im obigen Beispiel seit 1 eine Konstante ungleich Null ist, der { print } Aktionsblock wird für jeden Eingabedatensatz ausgeführt.

Ein weiterer Trick ist { print } ist der Standard-Aktionsblock, der von AWK verwendet wird, wenn Sie keinen explizit angeben. Der obige Befehl kann also verkürzt werden als:

awk 1 file
CREDITS,EXPDATE,USER,GROUPS
99,01 jun 2018,sylvain,team:::admin
52,01    dec   2018,sonia,team
52,01    dec   2018,sonia,team
25,01    jan   2019,sonia,team
10,01 jan 2019,sylvain,team:::admin
8,12    jun   2018,öle,team:support



17,05 apr 2019,abhishek,guest

Fast ebenso nutzlos wird das folgende AWK-Programm seine Eingabe verarbeiten, aber nichts für die Ausgabe erzeugen:

awk 0 file

2. Entfernen Sie einen Dateiheader

awk 'NR>1' file
99,01 jun 2018,sylvain,team:::admin
52,01    dec   2018,sonia,team
52,01    dec   2018,sonia,team
25,01    jan   2019,sonia,team
10,01 jan 2019,sylvain,team:::admin
8,12    jun   2018,öle,team:support



17,05 apr 2019,abhishek,guest

Denken Sie daran, dies ist das Äquivalent zum expliziten Schreiben von:

awk 'NR>1 { print }' file
99,01 jun 2018,sylvain,team:::admin
52,01    dec   2018,sonia,team
52,01    dec   2018,sonia,team
25,01    jan   2019,sonia,team
10,01 jan 2019,sylvain,team:::admin
8,12    jun   2018,öle,team:support



17,05 apr 2019,abhishek,guest

Dieser Einzeiler schreibt Aufzeichnungen der Eingabedatei mit Ausnahme der allerersten, da in diesem Fall die Bedingung 1>1 ist was offensichtlich nicht stimmt.

Da dieses Programm die Standardwerte für RS verwendet , in der Praxis wird die erste Zeile der Eingabedatei verworfen.

3. Zeilen in einem Bereich drucken

Dies ist nur eine Verallgemeinerung des vorherigen Beispiels und verdient nicht viele Erklärungen, außer && ist der logische and Betreiber:

awk 'NR>1 && NR < 4' file
99,01 jun 2018,sylvain,team:::admin
52,01    dec   2018,sonia,team

4. Nur-Leerraum-Zeilen entfernen

awk 'NF' file
CREDITS,EXPDATE,USER,GROUPS
99,01 jun 2018,sylvain,team:::admin
52,01    dec   2018,sonia,team
52,01    dec   2018,sonia,team
25,01    jan   2019,sonia,team
10,01 jan 2019,sylvain,team:::admin
8,12    jun   2018,öle,team:support
17,05 apr 2019,abhishek,guest

AWK teilt jeden Datensatz basierend auf dem im FS angegebenen Feldtrennzeichen in Felder auf Variable. Das Standard-Feldtrennzeichen ist ein-oder-mehrere-Leerzeichen (auch bekannt als Leerzeichen oder Tabulatoren). Mit diesen Einstellungen enthält jeder Datensatz, der mindestens ein Nicht-Leerzeichen enthält, mindestens ein Feld.

Mit anderen Worten, der einzige Fall, in dem NF 0 („false“) ist, wenn der Datensatz nur Leerzeichen enthält. Dieser Einzeiler druckt also nur Datensätze, die mindestens ein Nicht-Leerzeichen enthalten.

5. Entfernen aller Leerzeilen

awk '1' RS='' file
CREDITS,EXPDATE,USER,GROUPS
99,01 jun 2018,sylvain,team:::admin
52,01    dec   2018,sonia,team
52,01    dec   2018,sonia,team
25,01    jan   2019,sonia,team
10,01 jan 2019,sylvain,team:::admin
8,12    jun   2018,öle,team:support

17,05 apr 2019,abhishek,guest

Dieser Einzeiler basiert auf einer obskuren POSIX-Regel, die angibt, ob der RS auf die leere Zeichenfolge gesetzt ist, „dann werden Datensätze durch Sequenzen getrennt, die aus einem plus einer oder mehreren Leerzeilen bestehen.“

Erwähnenswert in der POSIX-Terminologie ist, dass eine Leerzeile eine vollständig leere Zeile ist. Zeilen, die nur Leerzeichen enthalten, zählen nicht als „Leerzeichen“.

6. Felder extrahieren

Dies ist wahrscheinlich einer der häufigsten Anwendungsfälle für AWK:das Extrahieren einiger Spalten der Datendatei.

awk '{ print $1, $3}' FS=, OFS=, file
CREDITS,USER
99,sylvain
52,sonia
52,sonia
25,sonia
10,sylvain
8,öle
        ,
,
,
17,abhishek

Hier setze ich explizit sowohl die Eingabe- als auch die Ausgabefeldtrennzeichen auf das Komma. Wenn AWK einen Datensatz in Felder aufteilt, speichert es den Inhalt des ersten Felds in $1, den Inhalt des zweiten Felds in $2 und so weiter. Ich verwende das hier nicht, aber erwähnenswert ist, dass $0 der gesamte Datensatz ist.

In diesem Einzeiler haben Sie vielleicht bemerkt, dass ich einen Aktionsblock ohne Muster verwende. In diesem Fall wird für das Muster 1 („true“) angenommen, sodass der Aktionsblock für jeden Datensatz ausgeführt wird.

Abhängig von Ihren Anforderungen wird möglicherweise nicht das erzeugt, was wir für Leer- oder Nur-Leerzeichen-Zeilen möchten. In diesem Fall könnte diese zweite Version etwas besser sein:

awk 'NF { print $1, $3 }' FS=, OFS=, file
CREDITS,USER
99,sylvain
52,sonia
52,sonia
25,sonia
10,sylvain
8,öle
        ,
17,abhishek

In beiden Fällen habe ich benutzerdefinierte Werte für FS übergeben und OFS auf der Kommandozeile. Eine andere Möglichkeit wäre die Verwendung eines speziellen BEGIN Block innerhalb des AWK-Programms, um diese Variablen zu initialisieren, bevor der erste Datensatz gelesen wird. Je nach Ihrem Geschmack schreiben Sie stattdessen vielleicht lieber Folgendes:

awk 'BEGIN { FS=OFS="," } NF { print $1, $3 }' file
CREDITS,USER
99,sylvain
52,sonia
52,sonia
25,sonia
10,sylvain
8,öle
        ,
17,abhishek

Erwähnenswert ist, dass Sie hier auch END verwenden können Blöcke, um einige Aufgaben auszuführen, nachdem der letzte Datensatz gelesen wurde. Wie wir es gerade sehen werden. Davon abgesehen gebe ich zu, dass dies alles andere als perfekt ist, da Nur-Leerraum-Zeilen nicht elegant gehandhabt werden. Wir werden bald eine mögliche Lösung sehen, aber vorher rechnen wir etwas…

7. Spaltenweise Berechnungen durchführen

AWK unterstützt die standardmäßigen arithmetischen Operatoren. Und konvertiert Werte je nach Kontext automatisch zwischen Text und Zahlen. Sie können auch Ihre eigenen Variablen verwenden, um Zwischenwerte zu speichern. All das ermöglicht es Ihnen, kompakte Programme zu schreiben, um Berechnungen mit Datenspalten durchzuführen:

awk '{ SUM=SUM+$1 } END { print SUM }' FS=, OFS=, file
263

Oder äquivalent mit += Kurzsyntax:

awk '{ SUM+=$1 } END { print SUM }' FS=, OFS=, file
263

Bitte beachten Sie, dass AWK-Variablen vor der Verwendung nicht deklariert werden müssen. Es wird angenommen, dass eine undefinierte Variable die leere Zeichenfolge enthält. Was nach den AWK-Typkonvertierungsregeln gleich der 0-Nummer ist. Aufgrund dieser Funktion habe ich mich nicht darum gekümmert, den Fall explizit zu behandeln, in dem $1 enthält Text (in der Überschrift), Leerzeichen oder einfach nichts. In all diesen Fällen zählt es als 0 und stört unsere Summierung nicht. Natürlich wäre es anders, wenn ich stattdessen Multiplikationen durchführen würde. Warum würden Sie also nicht den Kommentarbereich nutzen, um eine Lösung für diesen Fall vorzuschlagen?

8. Zählen der Anzahl nicht leerer Zeilen

Das END habe ich bereits erwähnt vorher regieren. Hier ist eine weitere mögliche Anwendung, um die Anzahl nicht leerer Zeilen in einer Datei zu zählen:

awk '/./ { COUNT+=1 } END { print COUNT }' file
9

Hier habe ich den COUNT verwendet Variable und inkrementiert (+=1 ) für jede Zeile, die mit dem regulären Ausdruck /./ übereinstimmt . Das ist jede Zeile, die mindestens ein Zeichen enthält. Schließlich wird der END-Block verwendet, um das Endergebnis anzuzeigen, nachdem die gesamte Datei verarbeitet wurde. Der Name COUNT ist nichts Besonderes . Ich hätte Count verwenden können , count , n , xxxx oder jeder andere Name, der den AWK-Variablenbenennungsregeln entspricht

Ist dieses Ergebnis jedoch korrekt? Nun, es hängt von Ihrer Definition einer „leeren“ Zeile ab. Wenn Sie nur Leerzeilen (nach POSIX) für leer halten, dann ist das richtig. Aber vielleicht möchten Sie auch Zeilen, die nur aus Leerzeichen bestehen, als leer betrachten?

awk 'NF { COUNT+=1 } END { print COUNT }' file
8

Diesmal ist das Ergebnis anders, da diese spätere Version auch reine Leerzeichen ignoriert, während die ursprüngliche Version nur Leerzeilen ignorierte. Kannst du den Unterschied sehen? Ich lasse Sie das selbst herausfinden. Zögern Sie nicht, den Kommentarbereich zu verwenden, wenn dies nicht klar genug ist!

Schließlich, wenn Sie nur an Datenzeilen interessiert sind und meine spezielle Eingabedatendatei gegeben ist, könnte ich stattdessen Folgendes schreiben:

awk '+$1 { COUNT+=1 } END { print COUNT }' file
7

Es funktioniert aufgrund der AWK-Typkonvertierungsregeln. Das unäre Plus im Muster erzwingt die Bewertung von $1 in einem numerischen Kontext. In meiner Datei enthalten Datensätze im ersten Feld eine Zahl. Nicht-Datensätze (Überschriften, Leerzeilen, Nur-Leerzeichen-Zeilen) enthalten Text oder nichts. Alle von ihnen sind gleich 0, wenn sie in Zahlen umgewandelt werden.

Beachten Sie, dass bei dieser neuesten Lösung auch ein Datensatz für einen Benutzer mit 0 Credits verworfen wird.

B. Verwenden von Arrays in AWK

Arrays sind eine leistungsstarke Funktion von AWK. Alle Arrays in AWK sind assoziative Arrays, sodass sie es ermöglichen, eine beliebige Zeichenfolge mit einem anderen Wert zu verknüpfen. Wenn Sie mit anderen Programmiersprachen vertraut sind, kennen Sie sie vielleicht als Hashes , assoziative Tabellen , Wörterbücher oder Karten .

9. Ein einfaches Beispiel für ein AWK-Array

Stellen wir uns vor, ich möchte das Gesamtguthaben für alle Benutzer wissen. Ich kann einen Eintrag für jeden Benutzer in einem assoziativen Array speichern, und jedes Mal, wenn ich auf einen Datensatz für diesen Benutzer stoße, erhöhe ich den entsprechenden im Array gespeicherten Wert.

awk '+$1 { CREDITS[$3]+=$1 }
     END { for (NAME in CREDITS) print NAME, CREDITS[NAME] }' FS=, file
abhishek 17
sonia 129
öle 8
sylvain 109

Ich gebe zu, das ist kein Einzeiler mehr. Hauptsächlich wegen for Schleife, die verwendet wird, um den Inhalt des Arrays anzuzeigen, nachdem die Datei verarbeitet wurde. Kommen wir also zurück zu kürzeren Beispielen:

10. Identifizieren doppelter Zeilen mit AWK

Arrays können, genau wie andere AWK-Variablen, sowohl in Aktionsblöcken als auch in Mustern verwendet werden. Indem wir davon profitieren, können wir einen Einzeiler schreiben, um nur doppelte Zeilen zu drucken:

awk 'a[$0]++' file
52,01    dec   2018,sonia,team

Der ++ operator ist der Post-Increment-Operator, der von der C-Sprachfamilie geerbt wurde (deren AWK ein stolzes Mitglied ist, dank Brian Kernighan, einer ihrer ursprünglichen Autoren).

Wie der Name schon sagt, erhöht der Post-Increment-Operator eine Variable („add 1“), aber erst nachdem ihr Wert für die Auswertung des Englobing-Ausdrucks übernommen wurde.

In diesem Fall a[$0] wird ausgewertet, um zu sehen, ob der Datensatz gedruckt wird oder nicht, und sobald die Entscheidung getroffen wurde, wird der Array-Eintrag in jedem Fall inkrementiert.

Wenn also ein Datensatz zum ersten Mal gelesen wird, a[$0] ist undefiniert und somit für AWK gleich Null. Dieser erste Datensatz wird also nicht auf die Ausgabe geschrieben. Dann wird dieser Eintrag von Null auf Eins geändert.
Das zweite Mal, wenn derselbe Eingabedatensatz gelesen wird, a[$0] ist jetzt 1. Das ist „wahr“. Die Zeile wird gedruckt. Davor wird jedoch der Array-Eintrag von 1 auf 2 aktualisiert. Und so weiter.

11. Doppelte Zeilen entfernen

Als Folge des vorherigen Einzeilers möchten wir möglicherweise doppelte Zeilen entfernen:

awk '!a[$0]++' file
CREDITS,EXPDATE,USER,GROUPS
99,01 jun 2018,sylvain,team:::admin
52,01    dec   2018,sonia,team
25,01    jan   2019,sonia,team
10,01 jan 2019,sylvain,team:::admin
8,12    jun   2018,öle,team:support


17,05 apr 2019,abhishek,guest

Der einzige Unterschied besteht in der Verwendung des logischen Nicht-Operators (! ), die den Wahrheitswert des Ausdrucks umkehren. Was falsch war, wird wahr, und was wahr war, wird falsch. Das logische Nicht hat absolut keinen Einfluss auf den ++ Post-Inkrement, das genauso funktioniert wie zuvor.

C. Magische Feld- und Datensatztrenner

12. Änderung der Feldtrenner

awk '$1=$1' FS=, OFS=';' file
CREDITS;EXPDATE;USER;GROUPS
99;01 jun 2018;sylvain;team:::admin
52;01    dec   2018;sonia;team
52;01    dec   2018;sonia;team
25;01    jan   2019;sonia;team
10;01 jan 2019;sylvain;team:::admin
8;12    jun   2018;öle;team:support

17;05 apr 2019;abhishek;guest

Dieses Programm setzt den FS und OFS Variable, um ein Komma als Trennzeichen für Eingabefelder und ein Semikolon als Trennzeichen für Ausgabefelder zu verwenden. Da AWK den Ausgabedatensatz nicht ändert, solange Sie kein Feld geändert haben, ist der $1=$1 Trick wird verwendet, um AWK zu zwingen, den Rekord zu brechen und ihn mithilfe des Ausgabefeldtrennzeichens neu zusammenzusetzen.

Denken Sie daran, dass hier der Standard-Aktionsblock { print } ist . Sie könnten das also expliziter umschreiben als:

awk '$1=$1 { print }' FS=, OFS=';' file
CREDITS;EXPDATE;USER;GROUPS
99;01 jun 2018;sylvain;team:::admin
52;01    dec   2018;sonia;team
52;01    dec   2018;sonia;team
25;01    jan   2019;sonia;team
10;01 jan 2019;sylvain;team:::admin
8;12    jun   2018;öle;team:support

17;05 apr 2019;abhishek;guest

Sie haben vielleicht bemerkt, dass beide Beispiele auch leere Zeilen entfernen. Wieso den? Denken Sie an die AWK-Konvertierungsregeln:Eine leere Zeichenfolge ist „falsch“. Alle anderen Strings sind „true“. Der Ausdruck $1=$1 ist eine Affektion, die $1 verändert . Allerdings ist dies auch ein Ausdruck. Und es ergibt den Wert von $1 – was für die leere Zeichenfolge „false“ ist. Wenn Sie wirklich alle Zeilen wollen, müssen Sie stattdessen vielleicht so etwas schreiben:

awk '($1=$1) || 1 { print }' FS=, OFS=';' file
CREDITS;EXPDATE;USER;GROUPS
99;01 jun 2018;sylvain;team:::admin
52;01    dec   2018;sonia;team
52;01    dec   2018;sonia;team
25;01    jan   2019;sonia;team
10;01 jan 2019;sylvain;team:::admin
8;12    jun   2018;öle;team:support



17;05 apr 2019;abhishek;guest

Erinnerst du dich an den && Operator? Es war das logische UND. || ist das logische ODER. Die Klammer ist hier aufgrund der Vorrangregeln der Operatoren erforderlich. Ohne sie wäre das Muster fälschlicherweise als $1=($1 || 1) interpretiert worden stattdessen. Ich lasse Sie als Übung testen, wie das Ergebnis dann anders ausgefallen wäre.

Und schließlich, wenn Sie nicht allzu begeistert von Arithmetik sind, wette ich, dass Sie diese einfachere Lösung bevorzugen werden:

awk '{ $1=$1; print }' FS=, OFS=';' file
CREDITS;EXPDATE;USER;GROUPS
99;01 jun 2018;sylvain;team:::admin
52;01    dec   2018;sonia;team
52;01    dec   2018;sonia;team
25;01    jan   2019;sonia;team
10;01 jan 2019;sylvain;team:::admin
8;12    jun   2018;öle;team:support



17;05 apr 2019;abhishek;guest

13. Entfernen mehrerer Leerzeichen

awk '$1=$1' file
CREDITS,EXPDATE,USER,GROUPS
99,01 jun 2018,sylvain,team:::admin
52,01 dec 2018,sonia,team
52,01 dec 2018,sonia,team
25,01 jan 2019,sonia,team
10,01 jan 2019,sylvain,team:::admin
8,12 jun 2018,öle,team:support
17,05 apr 2019,abhishek,guest

Dies ist fast das gleiche Programm wie das vorherige. Die Feldtrennzeichen habe ich jedoch auf ihren Standardwerten belassen. Daher werden mehrere Leerzeichen als Trennzeichen für Eingabefelder verwendet, aber nur ein Leerzeichen wird als Trennzeichen für Ausgabefelder verwendet. Dies hat den netten Nebeneffekt, Vielfache zu verschmelzen Leerzeichen in eins Leerzeichen.

14. Linien verbinden mit AWK

OFS haben wir bereits verwendet , das Ausgabefeldtrennzeichen. Wie Sie vielleicht erraten haben, hat es den ORS Gegenstück zur Angabe des Trennzeichens für den Ausgabesatz:

awk '{ print $3 }' FS=, ORS=' ' file; echo
USER sylvain sonia sonia sonia sylvain öle    abhishek

Hier habe ich nach jedem Datensatz ein Leerzeichen anstelle eines Zeilenumbruchzeichens verwendet. Dieser Einzeiler ist in einigen Anwendungsfällen ausreichend, hat aber dennoch einige Nachteile.

Ganz offensichtlich verwirft es keine reinen Leerzeichen (die zusätzlichen Leerzeichen nach öle kommen davon). Daher kann es sein, dass ich stattdessen einen einfachen regulären Ausdruck verwende:

awk '/[^[:space:]]/ { print $3 }' FS=, ORS=' ' file; echo
USER sylvain sonia sonia sonia sylvain öle abhishek

Es ist jetzt besser, aber es gibt immer noch ein mögliches Problem. Es wird offensichtlicher, wenn wir das Trennzeichen in etwas sichtbares ändern:

awk '/[^[:space:]]/ { print $3 }' FS=, ORS='+' file; echo
USER+sylvain+sonia+sonia+sonia+sylvain+öle+abhishek+

Am Ende der Zeile befindet sich ein zusätzliches Trennzeichen, da das Feldtrennzeichen hinter geschrieben wird jeder Datensatz. Einschließlich des letzten.

Um das zu beheben, werde ich das Programm umschreiben, um ein benutzerdefiniertes Trennzeichen vorher anzuzeigen den Datensatz, beginnend mit dem zweiten Ausgabedatensatz.

awk '/[^[:space:]]/ { print SEP $3; SEP="+" }' FS=, ORS='' file; echo
USER+sylvain+sonia+sonia+sonia+sylvain+öle+abhishek

Da ich mich selbst um das Hinzufügen des Trennzeichens kümmere, setze ich auch das standardmäßige AWK-Ausgabedatensatztrennzeichen auf den leeren String. Wenn Sie jedoch anfangen, sich mit Trennzeichen oder Formatierungen zu beschäftigen, kann es das Zeichen sein, das Sie über die Verwendung des printf nachdenken sollten Funktion anstelle von print Erklärung. Wie wir es gleich sehen werden.

D. Feldformatierung

Die Beziehung zwischen den Programmiersprachen AWK und C habe ich bereits erwähnt. Unter anderem erbt AWK von der Standardbibliothek der C-Sprache das mächtige printf Funktion, die eine große Kontrolle über die Formatierung des an die Ausgabe gesendeten Textes ermöglicht.

Der printf Die Funktion nimmt ein Format als erstes Argument, das sowohl reinen Text enthält, der wörtlich ausgegeben wird, als auch Platzhalter, die zum Formatieren verschiedener Abschnitte der Ausgabe verwendet werden. Die Wildcards sind durch den % gekennzeichnet Charakter. Am gebräuchlichsten ist %s (für Zeichenkettenformatierung), %d (für die Formatierung von Ganzzahlen) und %f (für die Formatierung von Fließkommazahlen). Da dies ziemlich abstrakt sein kann, sehen wir uns ein Beispiel an:

awk '+$1 { printf("%s ",  $3) }' FS=, file; echo
sylvain sonia sonia sonia sylvain öle abhishek

Sie können feststellen, dass das Gegenteil von print ist -Anweisung, die printf Funktion verwendet nicht den OFS und ORS Werte. Wenn Sie also ein Trennzeichen wünschen, müssen Sie es explizit erwähnen, wie ich es getan habe, indem Sie am Ende der Formatzeichenfolge ein Leerzeichen hinzufügen. Dies ist der Preis für die vollständige Kontrolle über die Ausgabe.

Obwohl dies überhaupt kein Formatbezeichner ist, ist dies eine hervorragende Gelegenheit, den \n vorzustellen Notation, die in jedem AWK-String verwendet werden kann, um ein Zeilenumbruchzeichen darzustellen.

awk '+$1 { printf("%s\n",  $3) }' FS=, file
sylvain
sonia
sonia
sonia
sylvain
öle
abhishek

15. Tabellenergebnisse erstellen

AWK erzwingt ein Datensatz-/Felddatenformat basierend auf Trennzeichen. Verwenden Sie jedoch den printf -Funktion können Sie auch eine tabellarische Ausgabe mit fester Breite erzeugen. Da jeder Formatbezeichner in einem printf -Anweisung kann einen optionalen Breitenparameter akzeptieren:

awk '+$1 { printf("%10s | %4d\n",  $3, $1) }' FS=, file
   sylvain |   99
     sonia |   52
     sonia |   52
     sonia |   25
   sylvain |   10
       öle |    8
  abhishek |   17

Wie Sie sehen können, füllt AWK sie durch Angabe der Breite jedes Felds links mit Leerzeichen auf. Bei Text ist es normalerweise vorzuziehen, rechts aufzufüllen, was mit einer negativen Breitenzahl erreicht werden kann. Außerdem möchten wir für ganze Zahlen Felder mit Nullen anstelle von Leerzeichen auffüllen. Dies kann durch eine explizite 0 vor der Feldbreite erreicht werden:

awk '+$1 { printf("%-10s | %04d\n",  $3, $1) }' FS=, file
sylvain    | 0099
sonia      | 0052
sonia      | 0052
sonia      | 0025
sylvain    | 0010
öle        | 0008
abhishek   | 0017

16. Umgang mit Fließkommazahlen

Der %f Format verdient nicht viele Erklärungen…

awk '+$1 { SUM+=$1; NUM+=1 } END { printf("AVG=%f",SUM/NUM); }' FS=, file
AVG=37.571429

… außer vielleicht zu sagen, dass Sie fast immer die Feldbreite und Genauigkeit des angezeigten Ergebnisses explizit festlegen möchten:

awk '+$1 { SUM+=$1; NUM+=1 } END { printf("AVG=%6.1f",SUM/NUM); }' FS=, file
AVG=  37.6

Hier beträgt die Feldbreite 6, was bedeutet, dass das Feld den Platz von 6 Zeichen einnimmt (einschließlich des Punktes und schließlich wie üblich links mit Leerzeichen aufgefüllt). Die Genauigkeit .1 bedeutet, dass wir die Zahl mit 1 Dezimalzahl nach dem Punkt anzeigen möchten. Ich lasse Sie raten, was %06.1 ist würde stattdessen angezeigt werden.

E. Zeichenkettenfunktionen in AWK verwenden

Zusätzlich zum printf -Funktion enthält AWK einige andere nette Funktionen zur Bearbeitung von Zeichenfolgen. In diesem Bereich haben moderne Implementierungen wie Gawk einen reichhaltigeren Satz interner Funktionen zum Preis einer geringeren Portabilität. Ich selbst beschränke mich hier auf einige wenige POSIX-definierte Funktionen, die überall gleich funktionieren sollten.

17. Text in Großbuchstaben umwandeln

Dieses verwende ich oft, weil es Internationalisierungsprobleme gut handhabt:

awk '$3 { print toupper($0); }' file
99,01 JUN 2018,SYLVAIN,TEAM:::ADMIN
52,01    DEC   2018,SONIA,TEAM
52,01    DEC   2018,SONIA,TEAM
25,01    JAN   2019,SONIA,TEAM
10,01 JAN 2019,SYLVAIN,TEAM:::ADMIN
8,12    JUN   2018,ÖLE,TEAM:SUPPORT
17,05 APR 2019,ABHISHEK,GUEST

Tatsächlich ist dies wahrscheinlich die beste und portabelste Lösung, um Text von der Shell aus in Großbuchstaben umzuwandeln.

18. Ändern eines Teils einer Zeichenfolge

Mit substr Befehl können Sie eine Zeichenfolge mit einer bestimmten Länge aufteilen. Hier verwende ich es, um nur das erste Zeichen des dritten Felds groß zu schreiben:

awk '{ $3 = toupper(substr($3,1,1)) substr($3,2) } $3' FS=, OFS=, file
CREDITS,EXPDATE,USER,GROUPS
99,01 jun 2018,Sylvain,team:::admin
52,01    dec   2018,Sonia,team
52,01    dec   2018,Sonia,team
25,01    jan   2019,Sonia,team
10,01 jan 2019,Sylvain,team:::admin
8,12    jun   2018,Öle,team:support
17,05 apr 2019,Abhishek,guest

Der substr Die Funktion nimmt die Anfangszeichenfolge, den (1-basierten) Index des ersten zu extrahierenden Zeichens und die Anzahl der zu extrahierenden Zeichen. Wenn das letzte Argument fehlt, substr nimmt alle restlichen Zeichen des Strings.

Also substr($3,1,1) wird zum ersten Zeichen von $3 ausgewertet , und substr($3,2) zu den restlichen.

19. Felder in Unterfelder aufteilen

Das AWK-Record-Field-Datenmodell ist wirklich nett. Manchmal möchten Sie jedoch Felder selbst in mehrere Teile aufteilen, basierend auf einem internen Trennzeichen:

awk '+$1 { split($2, DATE, " "); print $1,$3, DATE[2], DATE[3] }' FS=, OFS=, file
99,sylvain,jun,2018
52,sonia,dec,2018
52,sonia,dec,2018
25,sonia,jan,2019
10,sylvain,jan,2019
8,öle,jun,2018
17,abhishek,apr,2019

Etwas überraschend funktioniert dies sogar, wenn einige meiner Felder durch mehr als ein Leerzeichen getrennt sind. Meistens aus historischen Gründen, wenn das Trennzeichen ein einzelnes Leerzeichen ist, split wird berücksichtigen, dass „die Elemente durch Leerzeichen getrennt sind“. Und nicht nur von einem. Der FS Sondervariable folgt der gleichen Konvention.

Im allgemeinen Fall entspricht jedoch eine Zeichenkette einem Zeichen. Wenn Sie also etwas Komplexeres benötigen, müssen Sie daran denken, dass das Feldtrennzeichen ein erweiterter regulärer Ausdruck ist.

Sehen wir uns als Beispiel an, wie das Gruppenfeld gehandhabt wird, das ein mehrwertiges Feld mit einem Doppelpunkt als Trennzeichen zu sein scheint:

awk '+$1 { split($4, GRP, ":"); print $3, GRP[1], GRP[2] }' FS=, file
sylvain team
sonia team
sonia team
sonia team
sylvain team
öle team support
abhishek guest

Während ich erwartet hätte, dass bis zu zwei Gruppen pro Benutzer angezeigt werden, wird für die meisten nur eine angezeigt. Dieses Problem wird durch das mehrfache Vorkommen des Trennzeichens verursacht. Die Lösung lautet also:

awk '+$1 { split($4, GRP, /:+/); print $3, GRP[1], GRP[2] }' FS=, file
sylvain team admin
sonia team
sonia team
sonia team
sylvain team admin
öle team support
abhishek guest

Die Schrägstriche anstelle der Anführungszeichen kennzeichnen das Literal als regulären Ausdruck und nicht als einfache Zeichenfolge, und das Pluszeichen gibt an, dass dieser Ausdruck mit einem oder mehreren Vorkommen des vorherigen Zeichens übereinstimmt. In diesem Fall besteht also jedes Trennzeichen (aus der längsten Folge von) einem oder mehreren aufeinanderfolgenden Doppelpunkten.

20. Suchen und Ersetzen mit AWK-Befehlen

Apropos reguläre Ausdrücke, manchmal möchten Sie eine Ersetzung wie sed s///g durchführen Befehl, aber nur auf einem Feld. Der gsub Befehl ist das, was Sie in diesem Fall brauchen:

awk '+$1 { gsub(/ +/, "-", $2); print }' FS=, file
99 01-jun-2018 sylvain team:::admin
52 01-dec-2018 sonia team
52 01-dec-2018 sonia team
25 01-jan-2019 sonia team
10 01-jan-2019 sylvain team:::admin
8 12-jun-2018 öle team:support
17 05-apr-2019 abhishek guest

Der gsub Die Funktion benötigt einen regulären Ausdruck für die Suche, eine Ersatzzeichenfolge und die Variable, die den zu ändernden Text enthält. Wenn das später fehlt, wird $0 angenommen.

F. Arbeiten mit externen Befehlen in AWK

Ein weiteres großartiges Feature von AWK ist, dass Sie externe Befehle einfach aufrufen können, um Ihre Daten zu verarbeiten. Dafür gibt es grundsätzlich zwei Möglichkeiten:mit dem system Anweisung, ein Programm aufzurufen und es seine Ausgabe in den AWK-Ausgabestrom mischen zu lassen. Oder verwenden Sie eine Pipe, damit AWK die Ausgabe des externen Programms erfassen kann, um das Ergebnis genauer zu steuern.

Das mag für sich genommen ein riesiges Thema sein, aber hier sind ein paar einfache Beispiele, die Ihnen die Leistungsfähigkeit hinter diesen Funktionen zeigen.

21. Hinzufügen des Datums über einer Datei

awk 'BEGIN { printf("UPDATED: "); system("date") } /^UPDATED:/ { next } 1' file
UPDATED: Thu Feb 15 00:31:03 CET 2018
CREDITS,EXPDATE,USER,GROUPS
99,01 jun 2018,sylvain,team:::admin
52,01    dec   2018,sonia,team
52,01    dec   2018,sonia,team
25,01    jan   2019,sonia,team
10,01 jan 2019,sylvain,team:::admin
8,12    jun   2018,öle,team:support



17,05 apr 2019,abhishek,guest

In diesem AWK-Programm zeige ich zunächst die Arbeit UPDATED an. Dann ruft das Programm das externe date auf Befehl, der sein Ergebnis direkt nach dem von AWK zu diesem Zeitpunkt erzeugten Text an die Ausgabe sendet.
Der Rest des AWK-Programms entfernt einfach eine Update-Anweisung, die möglicherweise in der Datei vorhanden ist, und gibt alle anderen Zeilen aus (mit der Regel 1 ).

Beachten Sie das next Erklärung. Es wird verwendet, um die Verarbeitung des aktuellen Datensatzes abzubrechen. Dies ist eine Standardmethode zum Ignorieren einiger Datensätze aus der Eingabedatei.

22. Modifying a field externally

For more complex cases, you may need to consider the | getline VARIABLE idiom of AWK:

awk '+$1 { CMD | getline $5; close(CMD); print }' CMD="uuid -v4" FS=, OFS=, file
99,01 jun 2018,sylvain,team:::admin,5e5a1bb5-8a47-48ee-b373-16dc8975f725
52,01    dec   2018,sonia,team,2b87e9b9-3e75-4888-bdb8-26a9b34facf3
52,01    dec   2018,sonia,team,a5fc22b5-5388-49be-ac7b-78063cbbe652
25,01    jan   2019,sonia,team,3abb0432-65ef-4916-9702-a6095f3fafe4
10,01 jan 2019,sylvain,team:::admin,592e9e80-b86a-4833-9e58-1fe2428aa2a2
8,12    jun   2018,öle,team:support,3290bdef-fd84-4026-a02c-46338afd4243
17,05 apr 2019,abhishek,guest,e213d756-ac7f-4228-818f-1125cba0810f

This will run the command stored in the CMD variable, read the first line of the output of that command, and store it into the variable $5 .

Pay special attention to the close statement, crucial here as we want AWK to create a new instance of the external command each time it executes the CMD | getline Erklärung. Without the close statement, AWK would instead try to read several lines of output from the same command instance.

23. Invoking dynamically generated commands

Commands in AWK are just plain strings without anything special. It is the pipe operator that triggers external programs execution. So, if you need, you can dynamically construct arbitrary complex commands by using the AWK string manipulation functions and operators.

awk '+$1 { cmd = sprintf(FMT, $2); cmd | getline $2; close(cmd); print }' FMT='date -I -d "%s"'  FS=, file
99 2018-06-01 sylvain team:::admin
52 2018-12-01 sonia team
52 2018-12-01 sonia team
25 2019-01-01 sonia team
10 2019-01-01 sylvain team:::admin
8 2018-06-12 öle team:support
17 2019-04-05 abhishek guest

We have already met the printf Funktion. sprintf is very similar but will return the built string rather than sending it to the output.

24. Joining data

To show you the purpose of the close statement, I let you try out that last example:

awk '+$1 { CMD | getline $5; print }' CMD='od -vAn -w4 -t x /dev/urandom' FS=, file
99 01 jun 2018 sylvain team:::admin  1e2a4f52
52 01    dec   2018 sonia team  c23d4b65
52 01    dec   2018 sonia team  347489e5
25 01    jan   2019 sonia team  ba985e55
10 01 jan 2019 sylvain team:::admin  81e9a01c
8 12    jun   2018 öle team:support  4535ba30
17 05 apr 2019 abhishek guest  80a60ec8

As the opposite of the example using the uuid command above, there is here only one instance of od launched while the AWK program is running, and when processing each record, we read one more line of the output of that same process.

Schlussfolgerung

That quick tour of AWK certainly can’t replace a full-fledged course or tutorial on that tool. However, for those of you that weren’t familiar with it, I hope it gave you enough ideas so you can immediately add AWK to your toolbox.

On the other hand, if you were already an AWK aficionado, you might have found here some tricks you can use to be more efficient or simply to impress your friends.

However, I do not pretend been exhaustive. So, in all cases, don’t hesitate to share your favorite AWK one-liner or any other AWK tips using the comment section below!


Linux
  1. Erste Schritte mit Zsh

  2. Erste Schritte mit dem Linux-tac-Befehl

  3. Erste Schritte mit dem Linux-cat-Befehl

  4. Erste Schritte mit ls

  5. Erste Schritte mit PostgreSQL unter Linux

Erste Schritte mit Alpine Linux Apk-Befehlsbeispielen

Erste Schritte mit dem Nano-Texteditor [Leitfaden für Anfänger]

Erste Schritte mit Markdown [Leitfaden für Anfänger]

Erste Schritte mit dem SED-Befehl [Leitfaden für Anfänger]

Erste Schritte mit Tmux [Leitfaden für Anfänger]

Erste Schritte mit dem Tar-Befehl