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/
. Ised
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ällergrep
. 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öljandebar
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.
Så 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