Gensub auf mehreren Zeilen

Gensub auf mehreren Zeilen

Ich habe eine Datei, die viele zufällige Zeilen enthält wie

aaa bbb
ccc ddd
eee mark: 98 fff
ggg ggg jjjj iii
jjj kkkk

Ich möchte awk UND nur gensub verwenden, um die Zahl „98“ oben abzugleichen. Bisher habe ich den folgenden Code, aber ich glaube, er funktioniert nicht, weil ich gensub so einstellen muss, dass „\n“ wie jedes andere Zeichen behandelt wird.

cat file.txt | awk 'printf(gensub(/^.*mark: ([0-9]+).*$/,"\\1","g"))}'

Ich brauche als Ausgabe des obigen Codes nur „98“. Wie mache ich das?

BEARBEITEN

selbst wenn ich den Modifikator „s“ oder „m“ verwende, funktioniert es nicht wie es sollte, da meines Wissens der Modifikator „s“ dazu führen sollte, dass reguläre Ausdrücke . als jedes Zeichen einschließlich \n behandeln.

Antwort1

Sie scheinen zu glauben, dass awkdie Eingabe als mehrzeilige Zeichenfolge behandelt wird. Das ist nicht der Fall. Wenn Sie ein awk-Skript auf einer Datei ausführen, wird das Skript angewendet.zu jeder Zeile der Dateiseparat. Ihr gensubwurde also einmal pro Zeile ausgeführt. Sie können damit eigentlich machen, was Sie wollen, awkaber es ist wirklich nicht das beste Werkzeug für diese Aufgabe.

Soweit ich weiß, haben Sie eine große Datei und möchten nur eine Zahl drucken, die nach mark:einem Leerzeichen kommt. Wenn das der Fall ist, sind alle diese Ansätze einfacher als das Herumspielen mit gensub:

  1. Verwendung grepmit Perl-kompatiblen regulären Ausdrücken ( -P)

    $ grep -oP 'mark:\s*\K\d+' file 
    98
    

    Das -obewirkt, dass grepnur der übereinstimmende Teil der Zeile gedruckt wird. Das \Kist eine PCRE-Konstruktion, die bedeutet: „Alles, was vor diesem Punkt übereinstimmt, ignorieren.“

  2. sed

    $ sed -n 's/.*mark:\s*\([0-9]\+\).*/\1/p' file
    98
    

    Das -nunterdrückt die normale Ausgabe. Das pam Ende seddruckt nur, wenn die Ersetzung erfolgreich war. Der reguläre Ausdruck selbst erfasst eine Zahlenfolge mark:und 0 oder mehr Leerzeichen und ersetzt die gesamte Zeile mit dem, was erfasst wurde.

  3. Perl

    $ perl -ne 'print if s/.*mark:\s*(\d+).*/$1/' file
    98
    

    Das -nweist Perl an, eine Eingabedatei zeilenweise zu lesen und das durch angegebene Skript anzuwenden -e. Das Skript druckt alle Zeilen aus, bei denen die Ersetzung erfolgreich war.

Wenn Sie wirklich, wirklich verwenden möchten gensub, könnten Sie etwas wie Folgendes tun:

$ awk '/mark:/{print gensub(/.*mark:\s*([0-9]+).*/,"\\1","g")}' file
98

Persönlich würde ich es in awk folgendermaßen machen:

$ awk '/mark:/{gsub(/[^0-9]/,"");print}' file
98

Da Sie anscheinend versucht haben, awk dazu zu bringen, mehrzeilige Eingaben zu empfangen, können Sie dies folgendermaßen erreichen (vorausgesetzt, Ihre Datei enthält keine NULL-Zeichen):

$ awk '{print(gensub(/^.*mark: ([0-9]+).*$/,"\\1","g"))}' RS='\0' file
98

Das RS='\0'setzt den Eingabedatensatztrenner (das definiert eine „Zeile“ für awk) auf \0. Da Ihre Datei keine solchen Zeichen enthält, wird dadurch awkalles auf einmal gelesen.

Antwort2

Die kleinste Änderung, damit es funktioniert, ist:

cat file | awk '/mark:/{printf( "%s\n",gensub(/^.*mark: ([0-9]+).*$/,"\\1","g"))}'

Das /mark:/ dient zum Auswählen einer Zeile, die "mark:" enthält.
Aber warum wird dann ein printf benötigt? Das hier funktioniert auch:

cat file | awk '/mark:/{print(gensub(/^.*mark: ([0-9]+).*$/,"\\1","g"))}'

Aber das wäre ein „sinnloser Einsatz der Katze", da awk direkt aus einer Datei lesen könnte:

awk '/mark:/{print(gensub(/^.*mark: ([0-9]+).*$/,"\\1","g"))}' file

Bearbeiten:

Auf Benutzeranfrage: So verwenden Sie den regulären Ausdruck auf Datei und Zeichenfolge.

Nun, mit den von Ihnen festgelegten Regeln ist awk mit nur gensub nicht möglich.
Außerdem bedeutet die Idee, mit „matching with“ .*mark: ([0-9]+).*alles durch das Match in den Klammern zu ersetzen, dass die ganze Datei abgeglichen werden muss, um einen Teil zu extrahieren. Das ist einer der Gründe, warum grep erstellt wurde.

Benutz einfach:

grep -oP "mark: \K([0-9]+)" file

oder:

echo "$string" | grep -oP "mark: \K([0-9]+)"

Und Sie erhalten das Ergebnis.

verwandte Informationen