Grep regex NON contiene stringa


182

Sto passando un elenco di modelli regex a grep per verificare un file syslog. Di solito corrispondono a un indirizzo IP e una voce di registro;

grep "1\.2\.3\.4.*Has exploded" syslog.log

È solo un elenco di modelli come il "1\.2\.3\.4.*Has exploded" parte che sto passando, in un ciclo, quindi non posso passare "-v" per esempio.

Sono confuso nel tentativo di fare il contrario di quanto sopra, NON corrisponde a righe con un determinato indirizzo IP ed errore quindi "! 1.2.3.4. * È esploso" corrisponderà a righe syslog per qualsiasi cosa diversa da 1.2.3.4 che mi dice che è esploso . Io devo essere in grado di includere un IP non corrispondono.

Ho visto vari post simili su StackOverflor, tuttavia usano schemi regex con i quali non riesco a lavorare grep. Qualcuno può fornire un esempio funzionante per grepfavore?

AGGIORNAMENTO: Questo sta accadendo in una sceneggiatura come questa;

patterns[1]="1\.2\.3\.4.*Has exploded"
patterns[2]="5\.6\.7\.8.*Has died"
patterns[3]="\!9\.10\.11\.12.*Has exploded"

for i in {1..3}
do
 grep "${patterns[$i]}" logfile.log
done

Vuoi dire che a volte vuoi abbinare uno schema, ma altre volte vuoi abbinare tutto tranne un certo schema? (questo sembra un requisito strano, ma comunque). In tal caso, perché non iterare su due diversi elenchi di schemi?
beerbajay,

Beh, non sono molto ben informato su regex; Non voglio grep per "È esploso" perché non voglio sapere questo su ogni dispositivo di registrazione, quindi posso in qualche modo grep per "È esploso" e! 9.10.11.12 in una sola dichiarazione?
jwbensley,

Se devi assolutamente farlo in un'affermazione, i lookbehinds negativi sono la strada da percorrere, come suggerisce Neil. Vedi il mio commento lì.
beerbajay,

Usa la corrispondenza regex in stile PCRE e un'asserzione lookahead negativa, secondo la risposta di @Neil: le patterns[3]="\!9\.10\.11\.12.*Has exploded"modifiche patterns[3]="(?<!9\.10\.11\.12).*Has exploded"e le grep "${patterns[$i]}" logfile.logmodifiche a grep -P "${patterns[$i]}" logfile.logPCRE presuppongono più metacaratteri per impostazione predefinita, quindi potrebbe essere necessario rimuovere alcune delle fughe da altre espressioni corrispondenti.
Codex24,

Risposte:


342

grepcorrisponde, grep -vfa l'inverso. Se devi "abbinare A ma non B" di solito usi le pipe:

grep "${PATT}" file | grep -v "${NOTPATT}"

Questo sta andando nel mezzo di un loop come ho già detto e sto solo passando il PATTERN a grep, quindi non posso usare "-v" come ho già detto. Sto solo girando un elenco di PATTERN e passando a grep.
jwbensley,

1
Puoi davvero usare -ve puoi usarlo in un ciclo. Forse devi essere più specifico sui tuoi limiti, o forse hai un'idea sbagliata di come dovrebbe funzionare la tua sceneggiatura. Prova a pubblicare del codice.
beerbajay,

Grazie beerbajay, ho aggiunto un codice spezzato al post originale per dare un po 'di contesto. Capisci cosa intendo adesso?
jwbensley,

Questa risposta non è completamente corretta ma tu stavi praticamente scrivendo beerbajay, avevo bisogno di ripensare il ciclo e in uso -v alla fine. Grazie per il puntatore;)
jwbensley

1
E se A fosse composto da B? In altre parole, cosa succede se voglio abbinare linee senza A e linee con AB? Una pipe non funzionerà.
Pawamoy,

15
(?<!1\.2\.3\.4).*Has exploded

Devi eseguirlo con -P per avere un lookbehind negativo (espressione regolare Perl), quindi il comando è:

grep -P '(?<!1\.2\.3\.4).*Has exploded' test.log

Prova questo. Usa lookbehind negativo per ignorare la linea se è preceduta da 1.2.3.4. Spero che aiuti!


1
Sono abbastanza sicuro che grepnon supporta la ricerca. A meno che tu non stia usando Gnu grepe utilizzi il --Pparametro per farlo usare un motore PCRE.
Tim Pietzcker,

No, grep non supporta questo tipo di Regex; $ grep -P (? <\! 1 \ .2 \ .3 \ .4) test.log -bash: errore di sintassi vicino al token imprevisto `('
jwbensley

Avrai bisogno di citare la regex se contiene caratteri che sarebbero interpretati dalla shell.
beerbajay,

citazione corretta: grep -P '(?<!1\.2\.3\.4) Has exploded' test.logNota che il lookbehind funziona solo sui caratteri che precedono immediatamente la parte corrispondente dell'espressione, quindi se ci sono altre cose tra l'indirizzo e il messaggio, ad esempio 1.2.3.4 FOO Has exploded, questo non funzionerà.
beerbajay,

@TimPietzcker, molto attento. Lo aggiungerò alla domanda. Inoltre, tieni presente che c'è un .*aspetto negativo dopo che anche il suo esempio lo ha, immagino che potrebbe esserci un altro testo in mezzo.
Neil,

2
patterns[1]="1\.2\.3\.4.*Has exploded"
patterns[2]="5\.6\.7\.8.*Has died"
patterns[3]="\!9\.10\.11\.12.*Has exploded"

for i in {1..3}
 do
grep "${patterns[$i]}" logfile.log
done

dovrebbe essere lo stesso di

egrep "(1\.2\.3\.4.*Has exploded|5\.6\.7\.8.*Has died)" logfile.log | egrep -v "9\.10\.11\.12.*Has exploded"    
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.