Come grep -v ed anche escludere la riga successiva dopo la partita?


14

Come filtrare 2 righe per ogni riga corrispondente al regex grep?
questo è il mio test minimo:

SomeTestAAAA
EndTest
SomeTestABCD
EndTest
SomeTestDEFG
EndTest
SomeTestAABC
EndTest
SomeTestACDF
EndTest

E ovviamente ho provato ad es. grep -vA 1 SomeTestAAChe non funziona.

l'output desiderato è:

SomeTestABCD
EndTest
SomeTestDEFG
EndTest
SomeTestACDF
EndTest

grep -v 'SomeTextAA' | uniq?
DarkHeart,

Risposte:


14

È possibile utilizzare grepcon -P(PCRE):

grep -P -A 1 'SomeTest(?!AA)' file.txt

(?!AA)è il modello di lookahead negativo a larghezza zero che assicura che non ci sia AAdopo SomeTest.

Prova:

$ grep -P -A 1 'SomeTest(?!AA)' file.txt 
SomeTestABCD
EndTest
SomeTestDEFG
EndTest
SomeTestACDF
EndTest

qual è il carattere di fuga per i punti? come Some.Test.AA?
Behrooz,

1
@Behrooz Fuga punti da \.così grep -P -A 1 'SomeTest\.(?!AA)' file.txtogrep -P -A 1 'SomeTest(?!\.AA)' file.txt
heemayl

Questo funziona in questo caso particolare perché negli OP le linee di esempio si presentano in coppie, SomeTest*\nEndTestquindi esegui il grepping di tutte le righe corrispondenti SomeTest*ma non SomeTestAA+ una riga di contesto dopo la corrispondenza. Aggiungi alcune altre righe all'input (ad es. Aggiungi una riga foobardopo ogni EndTestriga) quindi riprova.
don_crissti,

1
@don_crissti è vero, ci ho già lavorato.
Behrooz,

@ Behrooz - ti interessa condividere con noi come hai lavorato e magari rispondere al mio commento sotto la tua domanda?
don_crissti,

4

Ecco una sedsoluzione ( -ncioè senza auto-stampa) che funziona con input arbitrari:

sed -n '/SomeTestAA/!p          # if line doesn't match, print it
: m                             # label m
//{                             # if line matches
$!{                             # and if it's not the last line
n                               # empty pattern space and read in the next line
b m                             # branch to label m (so n is repeated until a
}                               # line that's read in no longer matches) but
}                               # nothing is printed
' infile

quindi con un input come

SomeTestAAXX
SomeTestAAYY
+ one line
SomeTestONE
Message body
EndTest
########
SomeTestTWO
something here
EndTest
SomeTestAABC
+ another line
SomeTestTHREE
EndTest
SomeTestAA
+ yet another line

in esecuzione

sed -n -e '/SomeTestAA/!p;: m' -e '//{' -e '$!{' -e 'n;b m' -e '}' -e'}' infile

uscite

SomeTestONE
Message body
EndTest
########
SomeTestTWO
something here
EndTest
SomeTestTHREE
EndTest

cioè rimuove esattamente le linee che grep -A1 SomeTestAA infileselezionerebbero:

SomeTestAAXX
SomeTestAAYY
+ one line
--
SomeTestAABC
+ another line
--
SomeTestAA
+ yet another line

Interessante. Non mi rendevo conto che //abbinato /SomeTestAA/. Ho pensato, in questo caso, si sarebbe abbinato l'espressione negata: /SomeTestAA/!. (+1)
Peter

@ Peter.O - grazie! No, secondo le specifiche, un RE vuoto deve sempre corrispondere all'ultimo RE utilizzato nell'ultimo comando; il !non è parte del RE , si tratta di una sedcosa.
don_crissti,

3

Potresti avere più fortuna con qualcosa che considera le regioni multilinea come singoli record. Ce n'è uno sgrepche non ho usato molto.

C'è anche awk, in cui è possibile impostare il separatore dei record di input e il separatore dei record di output, come preferisci.

pat="^SomeTestAA"
awk  'BEGIN{ RS=ORS="\nEndTest\n"} !/'"$pat/" foo

La maggior parte del programma awk ha virgolette singole, ma alla fine cambio a virgolette doppie in modo da $patpoter espandere la variabile shell.


awk -vpat="^SomeTestAA" -vRS="\nEndTest\n" 'BEGIN{ ORS=RS } $0 !~ pat' file
Peter

3

Una possibilità è quella di utilizzare pErl compatible regular eXpression grep:

pcregrep -Mv 'SomeTestAA.*\n' file

L'opzione -Mconsente al modello di abbinare più di una riga.


1
@don_crissti Entrambe le righe verranno rimosse. Le specifiche di OP non coprono questo caso.
jimmij,

È abbastanza ovvio che l'esempio e la domanda dei PO non coprono questi casi, sono solo curioso di sapere come funziona (non ho familiarità con pcre) perché con un numero dispari di righe consecutive corrispondenti, funziona (rimuove anche la linea di contesto) e con un numero pari di linee consecutive corrispondenti, non riesce (non rimuove la linea di contesto dopo).
don_crissti,

Dato che (GNU) grepsupporta già PCRE (tramite l' -Popzione), qual è il vantaggio dell'utilizzo pcregrep?
arielf

@arielf grepnon supporta l' -Mopzione.
jimmij,

1

Utilizzando standard sed:

$ sed '/SomeTestAA/{ N; d; }' file
SomeTestABCD
EndTest
SomeTestDEFG
EndTest
SomeTestACDF
EndTest

La sedsceneggiatura analizza la riga di file di input per riga, e quando una linea corrisponde al modello SomeTestAA, i due sedcomandi di modifica Ne dvengono eseguiti. Il Ncomando aggiunge la riga successiva di input allo spazio del pattern (il buffer che sedpuò essere modificato), delimina lo spazio del pattern e avvia il ciclo successivo.


1

Ho provato con il comando Below sed e ha funzionato bene

comando

sed  '/SomeTestAA/,+1d' filename

produzione

SomeTestABCD
EndTest
SomeTestDEFG
EndTest
SomeTestACDF
EndTest

0

Puoi usare sedil dcomando GNU per cancellare una linea, e prefissarla con /pat/,+Nper selezionare le linee che corrispondono al modello e alle successive N linee. Nel tuo caso, N = 1 poiché desideri eliminare solo la riga successiva dopo una riga corrispondente:

sed -e '/SomeTestAAAA/,+1d'
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.