it-swarm.com.de

Begrenzen Sie die Grep-Ausgabe auf kurze Zeilen

Ich benutze oft grep, um Dateien mit einem bestimmten Eintrag wie diesem zu finden:

grep -R 'MyClassName'

Das Gute ist, dass es die Dateien und ihren Inhalt zurückgibt und die gefundene Zeichenfolge rot markiert. Das Schlimme ist, dass ich auch riesige Dateien habe, in denen der gesamte Text in einer einzigen großen Zeile geschrieben ist. Jetzt gibt grep zu viel aus, wenn Text in diesen großen Dateien gefunden wird. Gibt es eine Möglichkeit, die Ausgabe auf beispielsweise 5 Wörter links und rechts zu beschränken? Oder beschränken Sie die Ausgabe auf 30 Buchstaben links und rechts?

8
Socrates

grep selbst hat nur Optionen für den Kontext, der auf Zeilen basiert. Eine Alternative wird vorgeschlagen von dieser SU-Beitrag :

Eine Problemumgehung besteht darin, die Option 'only-matching' zu aktivieren und dann die Leistung von RegExp zu nutzen, um ein bisschen mehr als nur Ihren Text zu lesen:

grep -o ".\{0,50\}WHAT_I_M_SEARCHING.\{0,50\}" ./filepath

Wenn Sie die Farbhervorhebung verwenden, können Sie natürlich immer wieder nacheinander greifen, um nur die tatsächliche Übereinstimmung einzufärben:

grep -o ".\{0,50\}WHAT_I_M_SEARCHING.\{0,50\}"  ./filepath | grep "WHAT_I_M_SEARCHING"

Als weitere Alternative würde ich vorschlagen, fold den Text zu lesen und ihn dann zu lesen, zum Beispiel:

fold -sw 80 input.txt | grep ...

Die Option -s bewirkt, dass fold Wörter in die nächste Zeile verschoben werden, anstatt dazwischen zu brechen.

Oder verwenden Sie eine andere Methode, um die Eingabe entsprechend der Struktur Ihrer Eingabe in Zeilen aufzuteilen. (Die SU-Veröffentlichung hat sich zum Beispiel mit JSON befasst, also wäre es besser, jq usw. zu verwenden, um hübsch zu drucken, und grep ... oder einfach jq zu verwenden, um die Filterung selbst durchzuführen ... als eine der beiden oben angegebenen Alternativen .)


Diese GNU awk-Methode ist möglicherweise schneller:

gawk -v n=50 -v RS='MyClassName' '
  FNR > 1 { printf "%s: %s\n",FILENAME, p prt substr($0, 0, n)}
  {p = substr($0, length - n); prt = RT}
' input.txt
  • Sagen Sie awk, dass die Datensätze nach dem Muster, an dem wir interessiert sind (-v RS=...), und der Anzahl der Zeichen im Kontext (-v n=...) aufgeteilt werden sollen.
  • Jeder Datensatz nach dem ersten Datensatz (FNR > 1) ist einer, bei dem awk eine Übereinstimmung für das Muster gefunden hat.
  • Wir drucken also n nachgestellte Zeichen aus der vorherigen Zeile (p) und n führende Zeichen aus der aktuellen Zeile (substr($0, 0, n)) zusammen mit dem passenden Text für die vorherige Zeile (prt) [.____].
    • wir setzen p und prtnach dem Drucken, so dass der Wert, den wir setzen, von der nächsten Zeile verwendet wird
    • RT ist ein GNUism, deshalb ist dies GNU awk-spezifisch.

Für rekursive Suche, vielleicht:

find . -type f -exec gawk -v n=50 -v RS='MyClassName' 'FNR>1{printf "%s: %s\n",FILENAME, p prt substr($0, 0, n)} {p = substr($0, length-n); prt = RT}' {} +
15
muru

Die Verwendung von only-matching in Kombination mit einigen anderen Optionen (siehe unten) kann sehr nahe an dem sein, was Sie suchen, ohne den in der anderen Antwort erwähnten Verarbeitungsaufwand für reguläre Ausdrücke

grep -RnHo 'MyClassName'
  • n numerische Ausgabe, zeigt die Zeilennummer der Übereinstimmung
  • H Dateiname, zeigt den Dateinamen am Anfang der Übereinstimmungszeile an
  • o Nur Übereinstimmungen, nur die berechnete Zeichenfolge anzeigen, nicht die gesamte Zeile
1
Robert Riedl