Delete matching nth line until blank line in awk/sed/grep
I need to delete the nth matchin开发者_如何学Cg line in a file from the match up to the next blank line (i.e. one chunk of blank line delimited text starting with the nth match).
This will delete a chunk of text that starts and ends with a blank line starting with the fourth blank line. It also deletes those delimiting lines.
sed -n '/^$/!{p;b};H;x;/^\(\n[^\n]*\)\{4\}/{:a;n;/^$/!ba;d};x;p' inputfile
Change the first /^$/
to change the start match. Change the second one to change the end match.
Given this input:
aaa
---
bbb
---
ccc
---
ddd delete me
eee delete me
===
fff
---
ggg
This version of the command:
sed -n '/^---$/!{p;b};H;x;/^\(\n[^\n]*\)\{3\}/{:a;n;/^===$/!ba;d};x;p' inputfile
would give this as the result:
aaa
---
bbb
---
ccc
fff
---
ggg
Edit:
I removed an extraneous b
instruction from the sed
commands above.
Here's a commented version:
sed -n ' # don't print by default
/^---$/!{ # if the input line doesn't match the begin block marker
p; # print it
b}; # branch to end of script and start processing next input line
H; # line matches begin mark, append to hold space
x; # swap pattern space and hold space
/^\(\n[^\n]*\)\{3\}/{ # if what was in hold consists of 3 lines
# in other words, 3 copies of the begin marker
:a; # label a
n; # read the next line
/^===$/!ba; # if it's not the end of block marker, branch to :a
d}; # otherwise, delete it, d branches to the end automatically
x; # swap pattern space and hold space
p; # print the line (it's outside the block we're looking for)
' inputfile # end of script, name of input file
Any unambiguous pattern should work for the begin and end markers. They can be the same or different.
perl -00 -pe 'if (/pattern/) {++$count == $n and $_ = "$`\n";}' file
-00
is to read the file in "paragraph" mode (record separator is one or more blank lines)
$`
is Perl's special variable for the "prematch" (text in front of the matching pattern)
In AWK
/m1/ {i++};
(i==3) {while (getline temp > 0 && temp != "" ){}; if (temp == "") {i++;next}};
{print}
Transforms this:
m1 1
first
m1 2
second
m1 3
third delete me!
m1 4
fourth
m1 5
last
into this:
m1 1
first
m1 2
second
m1 4
fourth
m1 5
last
deleting the third block of "m1" ...
Running on ideone here
HTH!
Obligatory awk script. Just change n=2
to whatever your nth match should be.
n=2; awk -v n=$n '/^HEADER$/{++i==n && ++flag} !flag; /^$/&&flag{flag=0}' ./file
Input
$ cat ./file
HEADER
line1a
line2a
line3a
HEADER
line1b
line2b
line3b
HEADER
line1c
line2c
line3c
HEADER
line1d
line2d
line3d
Output
$ n=2; awk -v n=$n '/^HEADER$/{++i==n&&++flag} !flag; /^$/&&flag{flag=0}' ./file
HEADER
line1a
line2a
line3a
HEADER
line1c
line2c
line3c
HEADER
line1d
line2d
line3d
精彩评论