Ich möchte alle Dateien innerhalb eines Verzeichnisses und seiner Unterverzeichnisse nach Zeilen durchsuchen, die eine bestimmte Zeichenfolge enthalten, aber ich möchte diejenigen Ergebnisse ausschließen, die unmittelbar danach eine andere bestimmte Zeichenfolge in der Zeile enthalten.
Zum Beispiel das:
foo1 searchString bar
foo1 excludeString bar
foo2 searchString bar
something else
foo3 searchString bar
foo3 excludeString bar
foo4 searchString bar
sollte dies zurückgeben:
foo2 searchString bar
foo3 searchString bar
foo4 searchString bar
Ich weiß, dass -A
mehrere Zeilen gedruckt werden und das -v
Ergebnisse ausschließt. Aber meine derzeitige Herangehensweise grep -r -A 1 "searchString" | grep -v "excludeString"
kann offensichtlich nicht funktionieren.
Gibt es eine Möglichkeit, dem zweiten grep mitzuteilen, dass die vorherige Zeile ebenfalls entfernt werden soll, wenn eine Übereinstimmung gefunden wird? Oder auf eine andere Weise, wie ich das erreichen könnte?
Leistung ist nicht mein Hauptanliegen; Es wäre schön, wenn der Befehl relativ leicht zu merken ist.
-m
, um einen "Cursor" aus dem ersten Grep zu pflegen und dann den zweiten Grep auszuführen. Wenn Sie dies in eine Schleife einfügen, erhalten Sie möglicherweise die gewünschte Funktionalität.Antworten:
Sie können
p
erlc
ompatibler
egulare
xpressions verwendengrep
:Es wird gesucht,
searchString
gefolgt von einem beliebigen Zeichen.
, das null oder mehrmals wiederholt wird*
, gefolgt von einer neuen Zeile\n
, wenn sich kein (?!
) Muster.*excludeString
daneben befindet. Option-M
ist vorhanden, um mehrere Zeilen abzugleichen.quelle
grep -r -A 1 "searchString" | pcregrep -v -M "\n.*excludeString"
welche Art von funktioniert, aber Ihr Befehl ist kürzer und die Ausgabe ist schöner..
ist "any char" aber newline , sonst würde das nicht funktionieren.grep -P
(GNU):grep -Pzo '(?m)(searchString.*\n)(?!.*excludeString)' file
(aber ich konnte nicht verhindern, dass zusätzliche Zeilen ausgegeben wurden).searchString
besser abzustimmen istgrep -Pzo '(.*searchString.*$)(?!\n.*excludeString)'
.(?m)
).Mit
sed
:Wie es funktioniert:
/searchString/!d
löscht die Zeile, wenn sie nicht übereinstimmtsearchString
und liest eine neue Zeile ein, wodurch der Befehlszyklus erneut gestartet wird (dh die verbleibenden Befehle werden nicht mehr ausgeführt)searchString
, wirdsed
ausgeführt$!N;/\n.*excludeString/!P;D
- siehe HIER, wie es funktioniert. Der Unterschied besteht darin, dass hier das MusterexcludeString
nach dem\n
ewline-Zeichen gesucht wird, so dass eine Zeile mit beiden übereinstimmtsearchString
undexcludeString
weiterhin gedruckt wird, wenn keine Zeilenübereinstimmung folgtexcludeString
. Wenn es keine Zeile gab, die sowohl mitsearchString
als auchexcludeString
(dh der bekannten Eingabe) übereinstimmt, können Sie den\n.*
Teil löschen und ausführen:sed '/searchString/!d;$!N;/excludeString/!P;D' infile
quelle
D
stattd
.)