Ta bort rad som innehåller viss sträng och följande rad

Jag använder den här

cat foo.txt | sed "/bar/d"

för att ta bort rader som innehåller strängen bar i filen.

Jag vill dock ta bort dessa rader och raden direkt efter det . Helst i sed, awk eller annat verktyg som finns tillgängligt i MinGW32.

Det är en typ av omvänd av vad jag kan få i grep med -A och -B för att också skriva ut matchande rader som rader före / efter den matchade raden.

Finns det något enkelt sätt att uppnå det?

Kommentarer

  • Bara för information: Jag ' analyserar loggar där poster är tvålinjer. Så jag vill hitta en post som matchar mönstret och ta bort den såväl som nästa rad. Därför behöver jag ' inte hantera matchningslinjer i följd, men tack ändå för att dina svar är fullständiga!

Svar

Om du har GNU sed (så icke-inbäddad Linux eller Cygwin):

sed "/bar/,+1 d" 

Om du har bar på två på varandra följande rader, detta tar bort den andra raden utan att analysera den. Om du till exempel har en 3-radig fil bar / bar / foo, foo raden kommer att stanna.

Kommentarer

  • +1 för längden 🙂 I min speciella exempel Jag har ' t bar s i följd så den här är super lätt att komma ihåg.
  • sed '/bar/d' om du bara vill " Ta bort rad som innehåller viss sträng " och inte nästa.
  • Om jag vill ta bort alla rader efter matematik då?
  • @Pandya Att ' är annorlunda. Du kan använda t.ex. sed '/math/q'
  • @ A.K. Om du bara vill ta bort matchande rad är det ' ännu enklare: sed '/bar/d'

Svar

Om bar kan förekomma på rad i rad kan du göra:

awk "/bar/{n=2}; n {n--; next}; 1" < infile > outfile 

som kan anpassas för att radera mer än två rader genom att ändra 2 ovan med antalet rader som ska raderas inklusive den matchande.

Om inte, det ”görs enkelt i sed med @MichaelRollins” lösning eller:

sed "/bar/,/^/d" < infile > outfile 

Kommentarer

  • Det andra plus i AWK-lösningen är att jag kan ersätta /bar/ /bar|baz|whatever/. I sed verkar den syntaxen ' inte fungera.
  • @ jakub.g, jag har GNU sed ( v4.4 nu). Inte säker på de andra. Vad jag vet är att den använder " grundläggande " syntax för reguljära uttryck som standard det är därför ditt exempel inte ' fungerar inte. För att uppnå vad du vill kan du antingen sätta ett snedstreck framför varje vertikal linje eller så kan du be sed att använda " utökad " reguljära uttryck. Mer information här: gnu.org/software/sed/manual/html_node/… . Observera att detta även gäller grep. Här är ' mitt eget exempel: echo $'0a\n1b\n2c' | sed '/0a\|1b/d'.

Svar

Jag talar inte flytande, men det är lätt att göra det i awk:

awk "/bar/{getline;next} 1" foo.txt 

awk-skript läser: för en rad som innehåller fält, hämta nästa rad (getline) och hoppa över all efterföljande bearbetning (nästa). Mönstret 1 i slutet skriver ut de återstående raderna.

Uppdatering

Som påpekades i kommentaren fungerade ovanstående lösning inte med på varandra följande bar. Här är en reviderad lösning som tar hänsyn till den:

awk "/bar/ {while (/bar/ && getline>0) ; next} 1" foo.txt 

Vi fortsätter att läsa för att hoppa över alla / bar / rader.

Kommentarer

  • För att replikera grep -A 100% måste du också hantera valfritt antal på varandra följande bar rader korrekt (genom att ta bort hela blocket och en rad efter).

Svar

Du vill använda sed ”s skriptfunktioner för att uppnå detta.

$ sed -e "/bar/ { $!N d }" sample1.txt 

Exempeldata:

$ cat sample1.txt foo bar biz baz buz 

Kommandot ”N” lägger till nästa inmatningsrad i mönsterutrymmet. Detta i kombination med raden från mönstermatchningen (/ bar /) blir de rader som du vill radera. Du kan sedan radera normalt med kommandot ”d”.

Kommentarer

  • Hur skriver jag en ny rad i konsolen? Eller är detta endast skript?
  • @ jakub.g: med GNU sed: sed -e '/bar/{N;d}' sample1.txt

Svar

Om någon rad omedelbart efter en matchning ska tas bort måste ditt sed -program överväga matchningar i följd. Med andra ord, om du tar bort en rad efter en matchning som också matchar, bör du antagligen ta bort raden som följer den också.

Den implementeras helt enkelt – men du måste titta bakom lite .

printf %s\\n 0 match 2 match match \ 5 6 match match match \ 10 11 12 match 14 15 | sed -ne"x;/match/!{g;//!p;}" 

 0 6 11 12 15  

Det fungerar genom att byta mellan håll och mönster för varje inläst rad – så att den sista raden kan jämföras med strömmen varje gång. Så när sed läser en rad utbyter det innehållet i sina buffertar – och den föregående raden är då innehållet i dess redigeringsbuffert, medan den aktuella raden läggs i spärrutrymme.

sed kontrollerar föregående rad för en matchning till match och om dess ! hittades inte de två uttrycken i { -funktionen } körs. sed kommer g och hållutrymmet genom att skriva över mönsterutrymmet – vilket betyder att den aktuella raden är i både håll- och mönsterutrymmet och sedan kommer det // att kontrollera om det matchar det senast sammanställda reguljära uttrycket – match – och om det inte match är det p rinted.

Detta betyder att en rad bara skrivs ut om den inte match och den omedelbart föregående raden inte match . Det avstår också från onödiga byten för sekvenser av match es.

Om du vill ha en version som kan släppa ett godtyckligt antal rader inträffar efter en match skulle det behöva lite mer arbete:

printf %s\\n 1 2 3 4 match \ match match 8 \ 9 10 11 12 13 \ 14 match match \ 17 18 19 20 21 | sed -net -e"/match/{h;n;//h;//!H;G;s/\n/&/5;D;}" -ep 

. .. ersätt 5 med antalet rader (inklusive den matchade raden) som du vill ta bort …


1 2 3 4 12 13 14 21 

Lämna ett svar

Din e-postadress kommer inte publiceras. Obligatoriska fält är märkta *