Remove every line with specific string, and also the one above and below it

I would like to identify every line with a specific string, in this case: "Mamma".
I would like to remove that line, and also the line above it and below it. So the below

Where are all amazing Flats
Look At The Great Big White
Hey There Hot Mamma
You Are So hot Baby
I wish You were Mine
Hee How Yee Haw
Hey There Hot Mamma
Wait A minute
Hee Haw Yee Haw
Hey There Hot Mamma
A song Is Here
Make me a List

Becomes

Where are all amazing Flats
I wish You were Mine
Make me a List

I was wondering if anyone could help me out? I've googled but it is a little complex for Google

---------- Post updated at 05:14 PM ---------- Previous update was at 05:07 PM ----------

I think this might work

sed -n '/Mamma/{N;s/.*//;x;d;};x;p;${x;p;}' file | sed '/^$/d'

An awk approach by scanning file twice:

awk 'NR==FNR{if($0~/Mamma/) A[NR]=$0;next}!(A[FNR-1]) && !(A[FNR]) && !(A[FNR+1])' file file

Perhaps ed or ex would be simpler:

ed -s file <<-"EOF"
	g/Mamma/.-1,.+1d
	1,$p
EOF

And, if you want to modify the input file instead of just print the file contents with the specified lines deleted, change the:

	1,$p

to:

	w
4 Likes

Hi.

Solution with a relative of grep, cgrep:

#!/usr/bin/env bash

# @(#) s1	Demonstrate match+previous+successor, then invert to delete; cgrep.
# See: http://sourceforge.net/projects/cgrep/

# Utility functions: print-as-echo, print-line-with-visual-space, debug.
# export PATH="/usr/local/bin:/usr/bin:/bin"
LC_ALL=C ; LANG=C ; export LC_ALL LANG
pe() { for _i;do printf "%s" "$_i";done; printf "\n"; }
pl() { pe;pe "-----" ;pe "$*"; }
db() { ( printf " db, ";for _i;do printf "%s" "$_i";done;printf "\n" ) >&2 ; }
db() { : ; }
C=$HOME/bin/context && [ -f $C ] && $C column cgrep

FILE=${1-data1}

pl " Input data file $FILE (columnized):"
column $FILE

pl " Results:"
cgrep -D -V -1 +1 Mamma $FILE

exit 0

producing:

$ ./s1

Environment: LC_ALL = C, LANG = C
(Versions displayed with local utility "version")
OS, ker|rel, machine: Linux, 2.6.26-2-amd64, x86_64
Distribution        : Debian 5.0.8 (lenny, workstation) 
bash GNU bash 3.2.39
column - ( /usr/bin/column, 2007-11-20 )
cgrep ATT cgrep 8.15

-----
 Input data file data1 (columnized):
Where are all amazing Flats	Hey There Hot Mamma
Look At The Great Big White	Wait A minute
Hey There Hot Mamma		Hee Haw Yee Haw
You Are So hot Baby		Hey There Hot Mamma
I wish You were Mine		A song Is Here
Hee How Yee Haw			Make me a List

-----
 Results:
Where are all amazing Flats
I wish You were Mine
Make me a List

The cgrep code is at the URL noted in the script; it needs to be compiled.

Best wishes ... cheers, drl

Another way to do it in awk:

awk '/Mamma/ { s=x ; getline ; next } s { print s } { s=$0 } END { print s }' file

Assuming no duplication in records, could you get away with two grep commands?:-

grep -B1 Mamma infile > tempfile
grep -vf tempfile infile > outfile

Have I missed the point in trying to make it too simple?

# cat input_file                                                  
Where are all amazing Flats
Look At The Great Big White
Hey There Hot Mamma
You Are So hot Baby
I wish You were Mine
Hee How Yee Haw
Hey There Hot Mamma
Wait A minute
Hee Haw Yee Haw
Hey There Hot Mamma
A song Is Here
Make me a List

# grep -B1 Mamma input_file>/tmp/tfile$$                          

# cat /tmp/tfile$$                                                
Look At The Great Big White
Hey There Hot Mamma
--
Hee How Yee Haw
Hey There Hot Mamma
--
Hee Haw Yee Haw
Hey There Hot Mamma

# grep -vf /tmp/tfile$$ input_file      
Where are all amazing Flats
You Are So hot Baby
I wish You were Mine
Wait A minute
A song Is Here
Make me a List

# 

Robin