Con grep, come posso abbinare un modello e invertire abbinare un altro modello?


11

Con grep, voglio selezionare tutte le linee che corrispondono a un modello e che non corrispondono a un altro modello. Voglio essere in grado di utilizzare una singola invocazione in grepmodo da poter utilizzare l' --after-contextopzione (o --before-context, o --context).

-vnon è praticabile qui, poiché annulla tutti i modelli che passo a greputilizzare l' -eopzione.

Esempio

Voglio cercare la corrispondenza delle righe needle, ignorando la corrispondenza delle righe ignore me, con una riga del seguente contesto.

Ecco il mio file di input:

one needle ignore me
two
three
four needle
five

L'output che voglio è:

four needle
five

Come puoi vedere, questa ingenua soluzione non funziona:

$ cat file | grep --after-context=1 needle | grep -v 'ignore me'
two
---
four needle
five

Risposte:



8

Sembra che tu stia usando GNU . Con GNU grep, potresti passare il --perl-regexflag per attivare PCRE e quindi fornire un'asserzione lookahead negativa, esempio sotto

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

La cosa principale da notare qui è che (?:(?!STRING).)*è STRINGcome [^CHAR]*èCHAR


@ 1_CR ... Signore ... è fantastico ..: P qualcosa che sorride aack
Rahul Patil,

@RahulPatil. :-), sì GNU grep è così buono.
Iruvar,

Non è proprio quello che voglio. Voglio che funzioni se "ignorami" è prima o dopo "ago".
Flimm,

@RahulPatil, grazie, l'ho risolto nell'ultima versione
iruvar il

Molto utile. Soprattutto nel caso di grep con contesto in cui si desidera escludere linee strettamente corrispondenti ma senza una certa parte del modello. Vicino alla domanda originale ma non è la stessa cosa.
gennaio

2

Suggerirei invece di utilizzare awk poiché gestisce meglio l'IO a più righe. O 1) Inoltra i risultati a GNU awk con --\ncome separatore dei record, oppure 2) Esegui tutti gli abbinamenti in awk.

opzione 1

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

Produzione:

four needle                                                                                  
five
--

Nota, questa opzione cerca ignore me, imposta FS=1e confronta l'intero record per $1confrontare solo con la prima riga.

opzione 2

<file awk 'a-- > 0; $0 ~ re1 && $0 !~ re2 { print $0; a=after }' re1=needle re2='ignore me' after=1

Esistono più ignore mefile, quindi awk non funziona
Rahul Patil,

@RahulPatil: potresti riformulare o aggiungere maggiori dettagli alla tua domanda? Non capisco cosa stai chiedendo.
Thor,

@Thos prova il tuo esempio con questo file di input paste.ubuntu.com/6252860
Rahul Patil,

@RahulPatil: Capisco cosa intendi ora, l' opzione 1 presuppone che un --\ndelimitatore sia tra ciascun gruppo corrispondente, che non è presente se i gruppi sono adiacenti l'uno all'altro. Il modo in cui i gruppi adiacenti devono essere gestiti è specifico dell'attività, quindi questo non è necessariamente sbagliato. L'opzione 2 non dipende dal separatore e non è interessata.
Thor,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.