W grep, w jaki sposób mogę dopasować wzór i odwrócić dopasować inny wzór?

11

Za pomocą grepchcę wybrać wszystkie linie, które pasują do wzoru i które nie pasują do innego wzoru. Chcę móc użyć pojedynczego wywołania, grepaby móc skorzystać z --after-contextopcji (lub --before-context, lub --context).

-vnie jest tutaj wykonalne, ponieważ neguje wszystkie wzorce, które przekazuję grepprzy użyciu -eopcji.

Przykład

Chcę szukać pasujących linii needle, ignorując pasujące linie ignore me, z jedną linią następującego kontekstu.

Oto mój plik wejściowy:

one needle ignore me
two
three
four needle
five

Dane wyjściowe, których chcę, to:

four needle
five

Jak widać, to naiwne rozwiązanie nie działa:

$ cat file | grep --after-context=1 needle | grep -v 'ignore me'
two
---
four needle
five
Flimm
źródło

Odpowiedzi:

8

Wygląda na to, że używasz GNU . Z GNU grep możesz przekazać --perl-regexflagę, aby aktywować PCRE, a następnie podać negatywne stwierdzenie dotyczące przyszłości, przykład poniżej

grep --after-context=1 \
--perl-regex '^(?:(?!ignore me).)*needle(?:(?!ignore me).)*$' file.txt
four needle
five

Najważniejsze w tym miejscu jest (?:(?!STRING).)*to, STRINGco [^CHAR]*jestCHAR

iruvar
źródło
@ 1_CR ... Sir .. to jest niesamowite ..: P coś do smileraack
Rahul Patil
@RahulPatil. :-), tak GNU grep jest tak dobry.
iruvar
Nie do końca tego chcę. Chcę, żeby zadziałało, czy „ignoruj ​​mnie” występuje przed czy po „igle”.
Flimm
@RahulPatil, dzięki, naprawiłem to w najnowszej wersji
iruvar,
Bardzo przydatne. Zwłaszcza w przypadku grep z kontekstem, w którym chcesz wykluczyć ściśle pasujące linie, ale bez pewnej części wzoru. Blisko pierwotnego pytania, ale nie do końca takie samo.
Gaoithe
2

Sugerowałbym użycie zamiast tego awk, ponieważ lepiej obsługuje on wieloliniowe operacje we / wy. Albo 1) Prześlij wyniki do GNU awk --\nza pomocą separatora rekordów, lub 2) Wykonaj całe dopasowanie w awk.

opcja 1

<file grep -A1 needle | awk '!/ignore me/' RS='--\n' ORS='--\n'

Wynik:

four needle                                                                                  
five
--

Uwaga: ta opcja przeszukuje cały rekord ignore me, ustawia FS=1i dopasowuje, $1aby porównać tylko z pierwszym wierszem.

Opcja 2

<file awk 'a-- > 0; $0 ~ re1 && $0 !~ re2 { print $0; a=after }' re1=needle re2='ignore me' after=1
Thor
źródło
Czy ignore mew pliku jest wiele , awk nie działa
Rahul Patil
@RahulPatil: czy mógłbyś przeformułować lub dodać więcej szczegółów do swojego pytania? Nie rozumiem o co pytasz.
Thor,
@Thos przetestuj swój przykład za pomocą tego pliku wejściowego paste.ubuntu.com/6252860
Rahul Patil
@RahulPatil: Rozumiem, co masz na myśli, opcja 1 zakłada, że --\nmiędzy każdą dopasowaną grupą znajduje się separator, którego nie ma, jeśli grupy sąsiadują ze sobą. Sposób obsługi sąsiednich grup jest zależny od zadania, więc niekoniecznie jest to złe. Opcja 2 nie zależy od separatora i nie ma na nią wpływu.
Thor,