
Mit grep
möchte ich alle Zeilen auswählen, die einem Muster entsprechen und nicht einem anderen Muster. Ich möchte einen einzigen Aufruf von verwenden können, grep
damit ich die --after-context
Option (oder --before-context
, oder --context
) verwenden kann.
-v
ist hier nicht durchführbar, da es alle Muster negiert, die ich grep
mit der -e
Option übergebe.
Beispiel
Ich möchte nach übereinstimmenden Zeilen suchen und übereinstimmende Zeilen mit einer Zeile des folgenden Kontexts needle
ignorieren .ignore me
Hier ist meine Eingabedatei:
one needle ignore me
two
three
four needle
five
Die gewünschte Ausgabe ist:
four needle
five
Wie Sie sehen, funktioniert diese naive Lösung nicht:
$ cat file | grep --after-context=1 needle | grep -v 'ignore me'
two
---
four needle
five
Antwort1
Wenn Sie GNU grep haben, können Sie verwendenReguläre Ausdrücke in Perl, die eineNegationskonstrukt.
grep -A1 -P '^(?!.*ignore me).*needle'
Wenn Sie GNU grep nicht haben, können Sieemulieren Sie die Vorher/Nachher-Kontextoptionen in awk.
awk -v after=3 -v before=2 '
/needle/ && !/ignore me/ {
for (i in h) {
print h[i];
delete h[i];
}
until = NR + after;
}
{
if (NR <= until) print $0; else h[NR] = $0;
delete h[NR-before];
}
END {exit !until}
'
Antwort2
Sie scheinen GNU zu verwendengrep. Mit GNU grep können Sie das --perl-regex
Flag zur Aktivierung von PCRE übergeben und dann eine negative Lookahead-Assertion liefern, Beispiel unten
grep --after-context=1 \
--perl-regex '^(?:(?!ignore me).)*needle(?:(?!ignore me).)*$' file.txt
four needle
five
Das Wichtigste, was hier zu beachten ist, ist, (?:(?!STRING).)*
wie STRING
es [^CHAR]*
istCHAR
Antwort3
Ich würde stattdessen awk empfehlen, da es mehrzeilige IO besser handhabt. Entweder1)Leiten Sie die Ergebnisse an GNU awk weiter, wobei --\n
als Datensatztrennzeichen verwendet wird, oder2)Führen Sie alle Abgleiche in awk durch.
Option 1
<file grep -A1 needle | awk '!/ignore me/' RS='--\n' ORS='--\n'
Ausgabe:
four needle
five
--
Beachten Sie, dass diese Option den gesamten Datensatz durchsucht ignore me
und nur mit der ersten Zeile vergleicht FS=1
.$1
Option 2
<file awk 'a-- > 0; $0 ~ re1 && $0 !~ re2 { print $0; a=after }' re1=needle re2='ignore me' after=1