开发者

Delete matching nth line until blank line in awk/sed/grep

开发者 https://www.devze.com 2023-01-30 17:55 出处:网络
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 chu

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
0

精彩评论

暂无评论...
验证码 换一张
取 消