Manchmal (in einfachen Fällen) ist es möglich, das Feldtrennzeichen ( FS) anzupassen und auszuwählen, was mit einem übereinstimmen soll $field. Das Vorformatieren der Eingabe könnte ebenfalls hilfreich sein.
Anscheinend ist jemand anderer Meinung. Diese Webseite stammt aus dem Jahr 2005: tek-tips.com/faqs.cfm?fid=5674 Sie bestätigt, dass Sie übereinstimmende Gruppen in awk nicht wiederverwenden können.
Peter Tillemans
3
Ich bevorzuge 'perl -n -p -e ...' für fast alle Anwendungsfälle gegenüber awk, da es flexibler, leistungsfähiger und meiner Meinung nach eine vernünftigere Syntax hat.
Peter Tillemans
15
gawk! = awk. Sie sind verschiedene Tools und gawkan den meisten Orten standardmäßig nicht verfügbar.
Oli
6
Das OP hat speziell nach einer awk-Lösung gefragt, daher denke ich nicht, dass dies eine Antwort ist.
Joppe
6
@Joppe Sie können keine awk-Lösung geben, wenn es keine Lösung gibt. In Zeile 3 erkläre ich, dass AWK die Erfassung von Gruppen nicht unterstützt, und gab eine Alternative an, die das OP anscheinend zu schätzen wusste, weil diese Antwort akzeptiert wurde. Wie könnte ich diese Frage besser beantworten?
Peter Tillemans
335
Mit gawk können Sie die matchFunktion verwenden, um Gruppen in Klammern zu erfassen.
gawk 'match($0, pattern, ary) {print ary[1]}'
Beispiel:
echo "abcdef"| gawk 'match($0, /b(.*)e/, a) {print a[1]}'
Ausgänge cd.
Beachten Sie die spezifische Verwendung von Gawk, die die betreffende Funktion implementiert.
Für eine tragbare Alternative können Sie mit match()und ähnliche Ergebnisse erzielen substr.
Wie unterscheidet es sich von der Verwendung grep -o?
Bfontaine
@bfontaine Könnten grep -oerfasste Gruppen ausgegeben werden?
Olle Härstedt
1
@ OlleHärstedt Nein, das konnte es nicht. Es deckt Ihren Anwendungsfall nur ab, wenn Sie keine Erfassungsgruppen haben. In diesem Fall wird es hässlich mit verketteten grep -o.
Ed Morton: Das verdient eine Antwort auf höchster Ebene, würde ich sagen. edit: ähm ... das druckt RewriteRule (.*) http://www.mysite.net/$für mich, das ist mehr als die untergruppe.
Sie können die Erfassung auch in Vanilla Awk ohne Erweiterungen simulieren. Es ist jedoch nicht intuitiv:
Schritt 1. Verwenden Sie gensub, um Übereinstimmungen mit einem Zeichen zu umgeben, das nicht in Ihrer Zeichenfolge enthalten ist. Schritt 2. Verwenden Sie Split für den Charakter. Schritt 3. Jedes andere Element im geteilten Array ist Ihre Erfassungsgruppe.
$ echo 'ab cb ad' | awk '{split (gensub (/ a ./, SUBSEP "&" SUBSEP, "g", $ 0), cap, SUBSEP); Druckkappe [2] "|" Kappe [4]; } '
ab | ad
Ich bin mir fast sicher, dass gensubdas ein istgawk bestimmte Funktion ist. Was bekommen Sie von Ihrem awk, wenn Sie tippen awk --version; -?). Viel Glück für jeden.
Shellter
6
Ich bin mir völlig sicher, dass Gensub ein Gawk-Ismus ist, obwohl BusyBox Awk es auch hat. Diese Antwort könnte jedoch auch mit gsub implementiert werden:echo 'ab cb ad' | awk '{gsub(/a./,SUBSEP"&"SUBSEP);split($0,cap,SUBSEP);print cap[2]"|"cap[4]}'
dubiousjim
3
gensub () ist eine gawk-Erweiterung, das gawk-Handbuch sagt es eindeutig. Andere awk-Varianten können es ebenfalls implementieren, aber es ist immer noch nicht POSIX. Versuchen Sie gawk --posix '{gsub (...)}' und es wird sich beschweren
MestreLion
2
@MestreLion, du meinst, es wird sich beschweren gawk --posix '{gensub(...)}'.
zweifelhaft
1
Obwohl Sie sich geirrt haben, dass POSIX awk die gensubFunktion hat, wurde Ihr Beispiel auf ein sehr begrenztes Szenario angewendet: Das gesamte Muster ist gruppiert, es kann nicht mit allen übereinstimmen, key=(value)wenn ich nur die valueTeile extrahieren möchte .
Miau
2
Ich hatte ein wenig Probleme damit, eine Bash-Funktion zu entwickeln, die die Antwort von Peter Tillemans umschließt, aber hier ist, was ich mir ausgedacht habe:
Funktion regex {perl -n -e "/ $ 1 / && printf \"% s \ n \ "," '$ 1'}
Ich fand, dass dies für das folgende Argument für reguläre Ausdrücke besser funktioniert als die awk-basierte Bash-Funktion von opsb, da ich nicht möchte, dass die "ms" gedruckt wird.
Ich bevorzuge diese Lösung, da Sie die Teile der Gruppe sehen können, die die Erfassung begrenzen, während Sie sie auch weglassen. Könnte jemand erklären, wie das funktioniert? Ich kann diese Perl-Syntax in BASH nicht richtig zum Laufen bringen, weil ich sie nicht sehr gut verstehe - insbesondere die doppelten / einfachen Anführungszeichen$1
Demis
Es ist nicht etwas, was ich vorher oder seither getan habe, aber im Rückblick verkettet es zwei Zeichenfolgen, wobei die erste Zeichenfolge in doppelten Anführungszeichen steht (diese erste Zeichenfolge enthält eingebettete doppelte Anführungszeichen, die mit Backslash versehen sind) und die zweite Zeichenfolge in einfachen Anführungszeichen steht . Dann wird das Ergebnis dieser Verkettung als Argument an perl -e geliefert. Außerdem müssen Sie wissen, dass das erste $ 1 (das in doppelten Anführungszeichen) durch das erste Argument für die Funktion ersetzt wird, während das zweite $ 1 (das in einfachen Anführungszeichen) unberührt bleibt. Siehe dieses Beispiel
wytten
Ich verstehe, das macht jetzt etwas mehr Sinn. Wo also im Perl-Befehl befindet sich die Regex-Match- / Gruppenerfassungsdefinition? Ich sehe, Sie haben geschrieben '([0-9]*)ms$'- wird das als Argument angegeben (und die Zeichenfolge als weiteres Argument)? Und die Ausgabe von perl -ewird dann in den printfBefehl von bash eingefügt , um zu ersetzen %s, ist das richtig? Danke, ich hoffe, dass ich das nutzen kann.
Demis
1
Sie übergeben einen regulären Ausdruck in einfachen Anführungszeichen als einziges Argument an die Regex-Bash-Funktion. Beispiel
FS
) anzupassen und auszuwählen, was mit einem übereinstimmen soll$field
. Das Vorformatieren der Eingabe könnte ebenfalls hilfreich sein.gawk
(da es verwendetgensub
).Antworten:
Das war ein Spaziergang in die Vergangenheit ...
Ich habe awk vor langer Zeit durch perl ersetzt.
Anscheinend erfasst die AWK-Engine für reguläre Ausdrücke ihre Gruppen nicht.
Sie könnten in Betracht ziehen, etwas zu verwenden wie:
Das Flag -n bewirkt, dass Perl wie awk jede Zeile durchläuft.
quelle
gawk
! =awk
. Sie sind verschiedene Tools undgawk
an den meisten Orten standardmäßig nicht verfügbar.Mit gawk können Sie die
match
Funktion verwenden, um Gruppen in Klammern zu erfassen.Beispiel:
Ausgänge
cd
.Beachten Sie die spezifische Verwendung von Gawk, die die betreffende Funktion implementiert.
Für eine tragbare Alternative können Sie mit
match()
und ähnliche Ergebnisse erzielensubstr
.Beispiel:
Ausgänge
cd
.quelle
Dies ist etwas, das ich ständig brauche, also habe ich eine Bash-Funktion dafür erstellt. Es basiert auf der Antwort von Glenn Jackman.
Definition
Fügen Sie dies Ihrem .bash_profile usw. hinzu.
Verwendung
Erfassen Sie Regex für jede Zeile in der Datei
Erfassen Sie die erste Regex-Erfassungsgruppe für jede Zeile in der Datei
quelle
grep -o
?grep -o
erfasste Gruppen ausgegeben werden?grep -o
.Sie können GNU awk verwenden:
quelle
awk 'match($0, /.*(http.*?)\$/) { print substr($0,RSTART,RLENGTH) }'
RewriteRule (.*) http://www.mysite.net/$
für mich, das ist mehr als die untergruppe.RSTART
undRLENGTH
beziehen sich auf die Teilzeichenfolge, die mit dem MusterSie können die Erfassung auch in Vanilla Awk ohne Erweiterungen simulieren. Es ist jedoch nicht intuitiv:
Schritt 1. Verwenden Sie gensub, um Übereinstimmungen mit einem Zeichen zu umgeben, das nicht in Ihrer Zeichenfolge enthalten ist. Schritt 2. Verwenden Sie Split für den Charakter. Schritt 3. Jedes andere Element im geteilten Array ist Ihre Erfassungsgruppe.
quelle
gensub
das ein istgawk
bestimmte Funktion ist. Was bekommen Sie von Ihrem awk, wenn Sie tippenawk --version
; -?). Viel Glück für jeden.echo 'ab cb ad' | awk '{gsub(/a./,SUBSEP"&"SUBSEP);split($0,cap,SUBSEP);print cap[2]"|"cap[4]}'
gawk --posix '{gensub(...)}'
.gensub
Funktion hat, wurde Ihr Beispiel auf ein sehr begrenztes Szenario angewendet: Das gesamte Muster ist gruppiert, es kann nicht mit allen übereinstimmen,key=(value)
wenn ich nur dievalue
Teile extrahieren möchte .Ich hatte ein wenig Probleme damit, eine Bash-Funktion zu entwickeln, die die Antwort von Peter Tillemans umschließt, aber hier ist, was ich mir ausgedacht habe:
Ich fand, dass dies für das folgende Argument für reguläre Ausdrücke besser funktioniert als die awk-basierte Bash-Funktion von opsb, da ich nicht möchte, dass die "ms" gedruckt wird.
quelle
$1
'([0-9]*)ms$'
- wird das als Argument angegeben (und die Zeichenfolge als weiteres Argument)? Und die Ausgabe vonperl -e
wird dann in denprintf
Befehl von bash eingefügt , um zu ersetzen%s
, ist das richtig? Danke, ich hoffe, dass ich das nutzen kann.