Werfen wir einen Blick auf die Manpage von GNU awk:
FS
— Das Eingabefeld-Trennzeichen, standardmäßig ein Leerzeichen. Siehe Felder , oben.
Zu den Feldern Abschnitt!
Während jeder Eingabedatensatz gelesen wird, teilt gawk den Datensatz unter Verwendung des Werts von FS
in Felder auf Variable als Feldtrenner. Wenn FS
ein einzelnes Zeichen ist, werden Felder durch dieses Zeichen getrennt. Wenn FS
die Nullzeichenfolge ist, dann wird jedes einzelne Zeichen zu einem separaten Feld. Andernfalls FS
wird als vollständiger regulärer Ausdruck erwartet. Im speziellen Fall, dass FS
ein einzelnes Leerzeichen ist, Felder werden durch Reihen von Leerzeichen und/oder Tabulatoren und/oder Zeilenumbrüchen getrennt.
Hier ist eine pragmatische Zusammenfassung das gilt für alle wichtigen Awk-Implementierungen :
- GNU Awk (
gawk
) - der Standardwertawk
in einigen Linux-Distributionen - Mawk (
mawk
) - der Standardwertawk
in einigen Linux-Distributionen (z. B. frühere Versionen von Ubuntu) - BWK Awk - der Standard
awk
auf BSD-ähnlichen Plattformen, einschließlich macOS
Aktuelle Versionen von all diese Implementierungen folgen dem POSIX-Standard in Bezug auf field Trennzeichen (aber nicht aufzeichnen Trennzeichen).
Glossar:
-
RS
ist der Eingabe-Datensatz Trennzeichen , die beschreibt, wie die Eingabe in Datensätze aufgeteilt wird :- Der von POSIX vorgegebene Standardwert ist ein Zeilenumbruch , auch als
\n
bezeichnet unter; das heißt, die Eingabe wird in Zeilen aufgeteilt standardmäßig . - Am
awk
Befehlszeile vonRS
kann als-v RS=<sep>
angegeben werden . - POSIX beschränkt
RS
zu einem Literal, Einzelzeichen Wert, aber GNU Awk und Mawk unterstützen mehrere Zeichen Werte, die erweiterte reguläre Ausdrücke sein können (BWK Awk tut nicht unterstütze das).
- Der von POSIX vorgegebene Standardwert ist ein Zeilenumbruch , auch als
-
FS
ist das Eingabe-Feld Trennzeichen , die beschreibt, wie jeder Datensatz ist in Felder aufgeteilt ; es kann sich um einen erweiterten regulären Ausdruck handeln .- Am
awk
Befehlszeile vonFS
kann als-F <sep>
angegeben werden (oder-v FS=<sep>
). - Der von POSIX vorgeschriebene Standardwert ist formal ein Leerzeichen (
0x20
), aber dieses Leerzeichen ist nicht buchstäblich als (einziges) Trennzeichen interpretiert, hat aber besondere Bedeutung ; siehe unten.
- Am
Standardmäßig :
- beliebiger Lauf von Leerzeichen und/oder Tabs und/oder Zeilenumbrüche wird als Feldtrennzeichen behandelt
- wobei führende und nachlaufende Läufe ignoriert werden .
Beachten Sie das mit dem standardmäßigen Trennzeichen für Eingabedatensätze (RS
), \n
, Zeilenumbrüche normalerweise Geben Sie das Bild nicht als Feldtrenner ein , weil kein Datensatz selbst enthält \n
in diesem Fall.
Zeilenumbrüche als Feldtrenner tun ins Spiel kommen , jedoch:
- Wenn
RS
auf einen Wert gesetzt, der zu Datensätzen selbst führt enthält\n
Instanzen (z. B. wennRS
wird auf die leere Zeichenfolge gesetzt; siehe unten). - Allgemein , wenn der
split()
Die Funktion wird verwendet, um einen String ohne explizites Feldtrennargument in Array-Elemente aufzuteilen.- Obwohl die Eingabedatensätze enthält nicht
\n
Instanzen im Fall der VorgabeRS
In Kraft ist dersplit()
Funktion, wenn sie ohne ein explizites Feldtrenner-Argument für eine mehrzeilige Zeichenfolge aus einer anderen Quelle aufgerufen wird (z. B. eine Variable, die über-v
übergeben wird Option oder als Pseudo-Dateiname) immer behandelt\n
als Feldtrenner.
- Obwohl die Eingabedatensätze enthält nicht
Wichtige NICHT standardmäßige Überlegungen :
-
Zuweisen des leeren Zeichenfolge zu
RS
hat eine besondere Bedeutung :Es liest die Eingabe im Absatzmodus , was bedeutet, dass die Eingabe durch Läufe von nicht leeren Zeilen in Datensätze aufgeteilt wird , wobei führende und nachfolgende Leerzeilen ignoriert werden . -
Wenn Sie etwas anderes zuweisen als ein Literal Leerzeichen zu
FS
, die Interpretation vonFS
ändert sich grundlegend :- Eine Single Zeichen oder jedes Zeichen aus einem bestimmten Zeichensatz wird individuell anerkannt als Feldtrenner - nicht läuft davon, wie bei der Voreinstellung.
- Zum Beispiel das Setzen von
FS
bis[ ]
- obwohl es effektiv entspricht einem einzigen Leerzeichen - bewirkt jedes individuelle Leerzeichen in jedem Datensatz, der als Feldtrennzeichen behandelt werden soll. - Um Läufe zu erkennen , der Regex-Quantifizierer (Duplizierungssymbol)
+
muss benutzt werden; B.[\t]+
würde Läufe erkennen von Tabulatoren als einzelnes Trennzeichen.
- Zum Beispiel das Setzen von
- Führend und nachlaufend Trennzeichen werden NICHT ignoriert , und trennen Sie stattdessen leer Felder.
- Einstellung
FS
zum leeren String bedeutet, dass jedes Zeichen eines Datensatzes ist sein eigenes Feld .
- Eine Single Zeichen oder jedes Zeichen aus einem bestimmten Zeichensatz wird individuell anerkannt als Feldtrenner - nicht läuft davon, wie bei der Voreinstellung.
-
Wie von POSIX vorgeschrieben, wenn
RS
wird auf die leere Zeichenfolge gesetzt (Absatzmodus), Zeilenumbrüche (\n
) sind auch gelten als Feldtrenner , unabhängig vom Wert vonFS
.
- Mit
-P
in Kraft undRS
auf den leeren String setzen ,\n
ist noch als Feldtrenner behandelt:
gawk -P -F' ' -v RS='' '{ printf "<%s>, <%s>\n", $1, $2 }' <<< $'a\nb'
- Mit
-P
in Kraft und ein nicht leererRS
,\n
wird NICHT als Feldtrenner behandelt - das ist das obsolete Verhalten:
gawk -P -F' ' -v RS='|' '{ printf "<%s>, <%s>\n", $1, $2 }' <<< $'a\nb'
Ein Fix kommt bald , laut den Betreuern von GNU Awk; erwarten Sie es in Version 4.2 (kein Zeitrahmen angegeben).
(Dank an @JohnKugelman und @EdMorton für ihre Hilfe.)
'[ ]+' funktioniert bei mir. Führen Sie awk -W version
aus um die awk-Version zu erhalten. Meine ist GNU Awk 4.0.2
.
# cat a.txt
tcp 0 0 10.192.25.199:65002 0.0.0.0:* LISTEN
tcp 0 0 127.0.0.1:26895 0.0.0.0:* LISTEN
tcp 0 0 0.0.0.0:111 0.0.0.0:* LISTEN
tcp 0 0 0.0.0.0:18422 0.0.0.0:* LISTEN
tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN
tcp 0 0 10.192.25.199:8888 0.0.0.0:* LISTEN
tcp 0 0 0.0.0.0:50010 0.0.0.0:* LISTEN
tcp 0 0 0.0.0.0:50075 0.0.0.0:* LISTEN
tcp 0 0 10.192.25.199:8093 0.0.0.0:* LISTEN
tcp 0 0 0.0.0.0:8670 0.0.0.0:* LISTEN
Zum Beispiel möchte ich den Listen-Port erhalten. Also muss ich das awk-Standardtrennzeichen verwenden, das mit ':'
hinzugefügt wurde# cat a.txt | awk -F '[ ]+|:' '{print $5}'
65002
26895
111
18422
22
8888
50010
50075
8093
8670
Wenn Sie nur das Standardtrennzeichen testen möchten, können Sie
ausführen# cat a.txt | awk -F '[ ]+' '{print $4}'
10.192.25.199:65002
127.0.0.1:26895
0.0.0.0:111
0.0.0.0:18422
0.0.0.0:22
10.192.25.199:8888
0.0.0.0:50010
0.0.0.0:50075
10.192.25.199:8093
0.0.0.0:8670
Das Ergebnis ist wie erwartet.
Die Frage the default delimiter is only space for awk?
ist mehrdeutig, aber ich werde versuchen, beide Fragen zu beantworten, die Sie vielleicht stellen.
Der Standardwert von FS
Variable (die das Feldtrennzeichen enthält, das awk mitteilt, wie Datensätze beim Lesen in Felder getrennt werden sollen) ist ein einzelnes Leerzeichen.
Das, was awk verwendet, um Datensätze in Felder zu trennen, ist ein "Feldtrennzeichen", das ein regulärer Ausdruck mit einigen zusätzlichen Funktionen ist, die nur gelten, wenn das Feldtrennzeichen ein einzelnes Leerzeichen ist. Diese zusätzliche Funktionalität ist die:
- Führende und nachgestellte Leerzeichen werden bei der Feldaufteilung ignoriert.
- Felder werden durch Ketten von zusammenhängenden Leerzeichen getrennt, die Leerzeichen, Tabulatoren und Zeilenumbrüche enthalten.
- Wenn Sie ein wörtliches Leerzeichen als Feldtrennzeichen verwenden möchten, müssen Sie es als
[ ]
angeben Anstatt nur ein eigenständiges literales Leerzeichen, wie Sie es in einem regulären Ausdruck könnten.
Zusätzlich dazu, dass Feldtrennzeichen verwendet werden, um Datensätze beim Lesen der Eingabe in Felder aufzuteilen, werden sie in einigen anderen Kontexten verwendet, z. das 3. Argument für split()
, daher ist es wichtig, dass Sie wissen, welche Kontexte einen String, einen regulären Ausdruck oder einen Fieldsep erfordern, und die Manpage gibt dies jeweils klar an.
Obiges erklärt unter anderem dies:
$ echo ' a b c ' | awk '{printf "%d: <%s> <%s> <%s>\n", NF, $1, $2, $3}'
3: <a> <b> <c>
$ echo ' a b c ' | awk -F' ' '{printf "%d: <%s> <%s> <%s>\n", NF, $1, $2, $3}'
3: <a> <b> <c>
$ echo ' a b c ' | awk -F'[ ]' '{printf "%d: <%s> <%s> <%s>\n", NF, $1, $2, $3}'
5: <> <a> <b>
Wenn Sie also nicht verstehen, warum die ersten 2 dieselbe Ausgabe erzeugen, die letzte jedoch anders ist, fragen Sie bitte.