Grep Charaktere vor und nach dem Spiel?

144

Verwenden Sie diese:

grep -A1 -B1 "test_pattern" file

erzeugt eine Zeile vor und nach dem übereinstimmenden Muster in der Datei. Gibt es eine Möglichkeit, nicht Zeilen, sondern eine bestimmte Anzahl von Zeichen anzuzeigen?

Die Zeilen in meiner Datei sind ziemlich groß, daher bin ich nicht daran interessiert, die gesamte Zeile zu drucken, sondern beobachte die Übereinstimmung nur im Kontext. Irgendwelche Vorschläge dazu?

Legende
quelle
1
Duplikat von unix.stackexchange.com/q/163726 Nahe Duplikat von stackoverflow.com/q/2034799
sondra.kinsey

Antworten:

183

3 Zeichen vor und 4 Zeichen nach

$> echo "some123_string_and_another" | grep -o -P '.{0,3}string.{0,4}'
23_string_and
ДМИТРИЙ МАЛИКОВ
quelle
5
Eine gute Antwort für kleine Datenmengen, aber es wird langsam, wenn Sie> 100 Zeichen abgleichen - z. B. in meiner riesigen XML-Datei möchte ich vorher und nachher {1.200} und es ist zu langsam für die Verwendung.
Benubird
3
Die awk-Version von @amit_g ist viel schneller.
ssobczak
6
Unter Mac OS X nicht verfügbar, daher ist dies keine allgemein verfügbare Lösung. Die -E-Version (unten aufgeführt) ist eine bessere Lösung. Was ist -P? Lesen Sie weiter ... -P, --perl-regexp Interpretieren Sie PATTERN als regulären Perl-Ausdruck (PCRE, siehe unten). Dies ist sehr experimentell und grep -P kann vor nicht implementierten Funktionen warnen.
Xofo
2
Unter OSX installieren Sie über: brew install homebrew/dupes/grepund führen Sie es als aus ggrep.
Kenorb
1
Wie von @Benubird impliziert, ist dies in Bezug auf die Leistung unmöglich für große Dateien mit einer mäßig breiten Umgebung, die für das Spielziel gewünscht wird.
Matanster
113
grep -E -o ".{0,5}test_pattern.{0,5}" test.txt 

Dies entspricht bis zu 5 Zeichen vor und nach Ihrem Muster. Der Schalter -o weist grep an, nur die Übereinstimmung anzuzeigen, und -E, einen erweiterten regulären Ausdruck zu verwenden. Stellen Sie sicher, dass die Anführungszeichen um Ihren Ausdruck stehen, da dies sonst von der Shell interpretiert werden kann.

ekse
quelle
1
Gute Antwort, interessant, dass es auf 2 ^ 8-1 für die Länge in der {} begrenzt ist, also {0,255}funktioniert {0,256}gibtgrep: invalid repetition count(s)
CodeMonkey
Dies scheint erheblich weniger performant zu werden, wenn ich die Anzahl der übereinstimmenden Zeichen (5 -> 25 -> 50) erhöhe. Irgendeine Idee warum?
Adam Hughes
37

Du könntest benutzen

awk '/test_pattern/ {
    match($0, /test_pattern/); print substr($0, RSTART - 10, RLENGTH + 20);
}' file
amit_g
quelle
2
Funktioniert auch mit etwas größeren Dateien
Touko
4
Wie können Sie damit mehrere Übereinstimmungen pro Zeile finden?
Koox00
1
Welche Bedeutung hat die erste Zahl in den Paaren in geschweiften Klammern? Wie die Nullen in "grep -E -o". {0,5} test_pattern. {0,5} "test.txt"?
Lew Rockwell Fan
Es ist wirklich schneller, aber nicht so genau wie die Antwort von @ ekse.
Abdollah
24

Du meinst so:

grep -o '.\{0,20\}test_pattern.\{0,20\}' file

?

Das druckt bis zu zwanzig Zeichen auf jeder Seite von test_pattern. Die \{0,20\}Notation ist wie *, gibt jedoch null bis zwanzig Wiederholungen anstelle von null oder mehr an. Das -osagt, dass nur die Übereinstimmung selbst und nicht die gesamte Zeile angezeigt werden soll.

Ruakh
quelle
Dieser Befehl funktioniert nicht für mich:grep: Invalid content of \{\}
Alexander Pravdin
0

Mit gawkkönnen Sie die Übereinstimmungsfunktion verwenden:

    x="hey there how are you"
    echo "$x" |awk --re-interval '{match($0,/(.{4})how(.{4})/,a);print a[1],a[2]}'
    ere   are

Wenn Sie mit perleiner flexibleren Lösung einverstanden sind: Im Folgenden werden drei Zeichen vor dem Muster gefolgt vom tatsächlichen Muster und dann fünf Zeichen nach dem Muster gedruckt.

echo hey there how are you |perl -lne 'print "$1$2$3" if /(.{3})(there)(.{5})/'
ey there how

Dies kann auch auf Wörter anstatt nur auf Zeichen angewendet werden. Beim Folgen wird ein Wort vor der tatsächlich übereinstimmenden Zeichenfolge gedruckt.

echo hey there how are you |perl -lne 'print $1 if /(\w+) there/'
hey

Im Folgenden wird ein Wort nach dem Muster gedruckt:

echo hey there how are you |perl -lne 'print $2 if /(\w+) there (\w+)/'
how

Im Folgenden wird ein Wort vor dem Muster, dann das eigentliche Wort und dann ein Wort nach dem Muster gedruckt:

echo hey there how are you |perl -lne 'print "$1$2$3" if /(\w+)( there )(\w+)/'
hey there how
P ....
quelle
0

Sie können regexp grep zum Suchen und + second grep zum Hervorheben verwenden

echo "some123_string_and_another" | grep -o -P '.{0,3}string.{0,4}' | grep string

23_string_and

Geben Sie hier die Bildbeschreibung ein

Andrew Zhilin
quelle
0

Ich werde mich nie leicht an diese kryptischen Befehlsmodifikatoren erinnern, also habe ich die oberste Antwort genommen und sie in eine Funktion in meiner ~/.bashrcDatei umgewandelt:


cgrep() {
    # For files that are arrays 10's of thousands of characters print.
    # Use cpgrep to print 30 characters before and after search patttern.
    if [ $# -eq 2 ] ; then
        # Format was 'cgrep "search string" /path/to/filename'
        grep -o -P ".{0,30}$1.{0,30}" "$2"
    else
        # Format was 'cat /path/to/filename | cgrep "search string"
        grep -o -P ".{0,30}$1.{0,30}"
    fi
} # cgrep()

So sieht es in Aktion aus:

$ ll /tmp/rick/scp.Mf7UdS/Mf7UdS.Source

-rw-r--r-- 1 rick rick 25780 Jul  3 19:05 /tmp/rick/scp.Mf7UdS/Mf7UdS.Source

$ cat /tmp/rick/scp.Mf7UdS/Mf7UdS.Source | cgrep "Link to iconic"

1:43:30.3540244000 /mnt/e/bin/Link to iconic S -rwxrwxrwx 777 rick 1000 ri

$ cgrep "Link to iconic" /tmp/rick/scp.Mf7UdS/Mf7UdS.Source

1:43:30.3540244000 /mnt/e/bin/Link to iconic S -rwxrwxrwx 777 rick 1000 ri

Bei der fraglichen Datei handelt es sich um eine durchgehende 25-KByte-Zeile, und es ist hoffnungslos, mit regulärer Datei das zu finden, wonach Sie suchen grep.

Beachten Sie die zwei verschiedenen Möglichkeiten, wie Sie cgrepdiese Parallelenmethode aufrufen können grep.

Es gibt eine "raffiniertere" Möglichkeit, die Funktion zu erstellen, bei der "$ 2" nur übergeben wird, wenn sie gesetzt ist, wodurch 4 Codezeilen gespeichert werden. Ich habe es aber nicht zur Hand. So etwas wie ${parm2} $parm2. Wenn ich es finde, werde ich die Funktion und diese Antwort überarbeiten.

WinEunuuchs2Unix
quelle