Betrachten Sie das folgende Spielzeugbeispiel:
this is a line
this line contains FOO
this line is not blank
This line also contains FOO
Some random text
This line contains FOO too
Not blank
Also not blank
More random text
FOO!
Yet more random text
FOO!
Ich möchte also die Ergebnisse eines Grep für FOO, aber mit der zusätzlichen Falte, dass Linien, die den übereinstimmenden Linien folgen, enthalten sein sollten, solange sie nicht leer sind und selbst kein FOO enthalten. Die Übereinstimmungen würden also wie folgt aussehen, wobei die verschiedenen Übereinstimmungen getrennt wären:
MATCH 1
this line contains FOO
this line is not blank
MATCH 2
This line also contains FOO
MATCH 3
This line contains FOO too
Not blank
Also not blank
MATCH 4
FOO!
Yet more random text
MATCH 5
FOO!
Bonuspunkte (bildlich gesprochen) für ein einfaches einzeiliges Skript, das über die Befehlszeile ausgeführt werden kann.
ADDENDUM: Das Hinzufügen einer laufenden Anzahl der Übereinstimmungsnummern wäre sehr praktisch, wenn es nicht zu schwierig ist.
text-processing
grep
Faheem Mitha
quelle
quelle
Antworten:
Verwenden
awk
stattgrep
:Eine Version, die die Übereinstimmungen auflistet:
Beide
awk
Programme verwenden eine sehr einfache "Zustandsmaschine", um festzustellen, ob sie aktuell übereinstimmt oder nicht. Eine Übereinstimmung des MustersFOO
führt dazu, dass es in denmatching
Status wechselt, und eine Übereinstimmung des Musters^$
(eine leere Zeile) bewirkt, dass es in den Nicht-matching
Status wechselt.Die Ausgabe von Leerzeilen zwischen übereinstimmenden Datensätzen erfolgt bei Zustandsübergängen von
matching
(entweder inmatching
oder in Nicht-matching
).Das erste Programm druckt eine beliebige Zeile im
matching
Status.Das zweite Programm sammelt Zeilen in einer
buf
Variablen, wenn es sich in einemmatching
Zustand befindet. Dies wird geleert (geleert), nachdem es möglicherweise gedruckt wurde (abhängig vom Status), zusammen mit einemMatch N
Etikett bei Statusübergängen (wenn das erste Programm eine leere Zeile ausgeben würde).Ausgabe dieses letzten Programms auf die Beispieldaten:
quelle
Jeder Block nicht leerer Zeilen in der Ausgabe ist ein einzelner Block übereinstimmender Daten von der Eingabe. Die Anzahl der Zeilenumbrüche variiert.
Diese
-n
); dann/FOO/{x;P;x}
- verwendet den leeren Haltebereich);/FOO/
) beginnen und in leeren Zeilen (/^$/
) enden ; und schlussendlichp
).quelle
Ich denke nicht, dass dies mit machbar ist
grep
, aber es ist mit AWK:Mit einer Anzahl von Übereinstimmungen:
In beiden Fällen bestimmen die ersten beiden Blöcke, ob der aktuelle Datensatz in die Ausgabe kopiert werden soll. Wenn der aktuelle Datensatz mit „FOO“ übereinstimmt, wird der erste Block
matched
auf 1 gesetzt und gibt bei Bedarf einen leeren Datensatz aus (um die bevorstehende Ausgabe von der vorherigen Übereinstimmung zu trennen). In der zweiten Variante wird auch dermatches
Zähler erhöht und ein Header ausgegeben. Wenn der aktuelle Datensatz leer ist, wird der zweite Blockmatched
auf 0 gesetzt. Dermatched
Zustand " Einsam" gibt den aktuellen Datensatz aus, wenn ermatched
1 ist.quelle
Ich habe eine
pcregrep
Lösung und einepython
Lösung aufgenommen.Multiline Grep-Lösung
Wenn Sie
pcregrep
installiert haben, können Sie ein mehrzeiliges Muster verwenden, z^.*FOO.*$\n?(^.*\S.*$\n?)*
. B.:Der Unterausdruck stimmt
^.*FOO.*$\n?
mit jeder Zeile überein, die die Zeichenfolge enthält,FOO
und der Unterausdruck stimmt(^.*\S.*$\n?)*
mit einer beliebigen Anzahl nachfolgender Zeilen überein, die ein Nicht-Leerzeichen enthalten.Python-Lösung
Hier ist ein Python-Skript, das tun soll, was Sie wollen:
Sie würden es so laufen lassen:
quelle
'(?s)^\N*FOO.*?(?=\Z|\n\n|\N*FOO\N*)'
, aber +1Eine ähnliche Variante, bei
FOO
der leicht etwas anderes geändert werden könnte:Das Weglassen der abschließenden Leerzeile aus dem Standarddruck bleibt dem Leser als Übung überlassen ;-)
quelle
Eine Möglichkeit kann die Verwendung des
Perl's
Bereichsoperators sein...
:Falls die zusätzlichen Leerzeilen ein Problem darstellen, können Sie den folgenden Code verwenden, wobei Sie den Bereichsoperator im skalaren Kontext verwenden, um einen Blick in die Werte der Zustandsmaschine zu werfen und darauf basierende Aktionen auszuführen.
Hinweis :
$/
= RS = "\ n"$,
= OFS = ""Hier ist eine andere Methode, um die Pbm anzugehen, diesmal mit der
paragraph mode
von Perl. Wir lesen jeweils einen Absatz ein und teilen sie in Zeilenumbrüchen in Felder auf.Dann stellen wir sicher, dass nur die Paras behandelt werden, in denen sich der String Foo befindet. Schließlich drucken wir die Felder mit der Einschränkung, dass foo-haltige Felder speziell behandelt werden. Auch hier behandeln wir das erste Feld anders als die anderen.
quelle
Hier ist ein Einzeiler, der möglicherweise nicht genau den Kriterien entspricht, aber für die meisten Zwecke nahe genug kommt.
Erste Regelsätze,
p=1
wenn FOO angezeigt wird. Die zweite Regel gibt die aktuelle Zeile aus, wenn p nicht Null ist. Die dritte Regel wird festgelegt,p=0
wenn die Zeile (bereits gedruckt) leer ist. Tauschen Sie die zweite und dritte Regel aus, wenn der Terminator für leere Zeilen nicht ausgegeben werden soll.Dies ist eine Variante, die die Übereinstimmungen nummeriert und trennt, wenn mehrere FOO-Instanzen vorhanden sind, die nicht durch Leerzeilen getrennt sind
quelle