Wie kann ich ein Verzeichnis anhand des Inhalts zweier aufeinanderfolgender Zeilen durchsuchen?


11

Wie kann ich ein Verzeichnis nach Zeilen durchsuchen , die "Foo" enthalten, aber nur Übereinstimmungen erhalten, wenn die nächste Zeile auch "Bar" enthält?


Das Problem ist jetzt völlig anders als beim Original: / Vielleicht ist es besser, die alten Versionen zurückzusetzen und eine andere zu POSTEN? Außerdem ist mir die neue Frage nicht klar.
Gilles Quenot

@sputnick - wie so? Ich habe ein Verzeichnis angegeben, als ich die Frage zum ersten Mal gestellt habe. Ich habe es nur gewagt, weil die Leute es nicht bemerkt haben.
Nathan Long

Egal, das wird funktionieren, ich werde meinen POST entsprechend bearbeiten.
Gilles Quenot

Antworten:


7

@ warl0ck zeigte mir die richtige Richtung mit pcregrep, aber ich sagte "enthält", nicht "ist", und ich fragte nach einem Verzeichnis, nicht nach einer Datei.

Das scheint bei mir zu funktionieren.

pcregrep -rMi 'Foo(.*)\n(.*)Bar' .

6

Grep selbst scheint es nicht zu unterstützen, verwenden Sie stattdessen pcregrep:

Foo
Bar
Foo
abc

pcregrep -M "Foo\nBar" file

Bekam:

Foo
Bar

3
Das OP sagte das nicht Foound Barwürde die gesamte Linie umfassen.
Tobrobinson

6

Mit einem sedSkript:

#!/bin/sed -nf

/^Foo/{
    h         # put the matching line in the hold buffer
    n         # going to nextline
    /^Bar/{   # matching pattern in newline
        H     # add the line to the hold buffer
        x     # return the entire paragraph into the pattern space
        p     # print the pattern space
        q     # quit the script now
    }
}

Um es zu benutzen :

chmod +x script.sed
printf '%s\n' * | ./script.sed

Das printfhier , um alle Dateien in einer Zeile jedem, im aktuellen Verzeichnis angezeigt und übergibt es an sed.

Hinweis : Dies ist nach alphabetischer Reihenfolge sortiert.

Weitere Infos von nützlich pattern spaceund hold space HIER .

grymoire.com hat wirklich gute Sachen zum shellProgrammieren.


Was h, n, H, x, p, qbedeutet das? Sehr interessant.
Yamaneko

Siehe meine Kommentare. Weitere Infos unter pattern space& hold space: grymoire.com/Unix/Sed.html#uh-56 oder in Französisch commentcamarche.net/faq/9536-sed-introduction-a-sed-part-i
Gilles Quenot

POST angepasst, um an einem Verzeichnis zu arbeiten
Gilles Quenot

4

Wenn Sie grepnur verwenden, können Sie die folgende Pipe erstellen:

grep -A1 'Foo' input_file | grep -B1 'Bar' | grep 'Foo'

Der erste greperhält alle Zeilen, die enthalten Foo, sowie die Zeile nach dem Spiel. Dann erhalten wir Zeilen, die Barsowohl die Zeile als auch die Zeile vor dem Match enthalten, und extrahieren schließlich die Zeilen aus dieser Ausgabe, die enthalten Foo.

EDIT: Wie Manatwork hervorhob , gibt es einige problematische Fälle zu beachten . Obwohl es sich aufgrund der greplinienorientierten Funktionalität um eine interessante Herausforderung handelt, ist jede Lösung wahrscheinlich ein "Hack", und Sie sollten wahrscheinlich etwas verwenden, pcregrepdas für die jeweilige Aufgabe besser geeignet ist.


Nett. Ich fragte allerdings nach einem Verzeichnis; das scheint zu funktionieren:find . -name '*.txt' | xargs grep -A1 'Foo' | grep -B1 'Bar'
Nathan Long

Dadurch werden auch Vorkommen mit "Foo" und "Bar" in derselben Zeile aufgelistet.
Manatwork

@manatwork: Zeilen, die "Foo" und "Bar" enthalten, sind "Zeilen, die" Foo "enthalten", was gefragt wurde.
Tobrobinson

1
@tojrobinson, was ist mit dem Teil "aber nur Übereinstimmungen erhalten, wenn die nächste Zeile auch" Bar "enthält"? pastebin.com/Yj8aeCEA
Manatwork

3

Während ich Nathans Lösung mit bevorzuge pcregrep, ist hier die Lösung nur mit grep

grep -o -z -P  'Foo(.*)\n(.*)Bar' file

Erklärung der Optionen:

  • -oNur passendes Teil drucken. Erforderlich, da durch Einfügen von -zdie gesamte Datei ausgedruckt wird (es sei denn, irgendwo ist eine \ 0 vorhanden).
  • -z Behandeln Sie die Eingabe als eine Reihe von Zeilen, die jeweils durch ein Null-Byte (das ASCII-NUL-Zeichen) anstelle einer neuen Zeile abgeschlossen werden.
  • -P Perl-Regex-Syntax

BEARBEITEN: Diese Version druckt ganze übereinstimmende Zeilen aus

    grep -o -P -z  '(.*)Foo(.*)\n(.*)Bar(.*)' file

1
Cooler Trick was -z. Ein "(. *)" Vor und nach dem gesamten Ausdruck würde dazu führen, dass die gesamten übereinstimmenden Zeilen ausgegeben werden. Derzeit werden Teilzeichenfolgen vor "Foo" und nach "Bar" nicht angezeigt.
Manatwork

1

Mit awk:

awk '/bar/ && prev != "" {print FILENAME ": " prev "\n" FILENAME ": " $0}
     /foo/ {prev=$0; next}
     {prev=""}' file1...

(Allgemeiner Hinweis zur awk-Einschränkung: Beachten Sie, dass einige Dateinamen "=" Zeichen enthalten müssen, ./filenameanstatt sie filenamean awk zu übergeben.)

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.