leeand00
leeand00

Reputation: 26402

Deleting n lines in both directions and the match in sed?

Deleting the match and two lines before it works:

sed -i.bak -e '/match/,-2d' someCommonName.txt

Deleting the match and two lines after it works:

sed -i.bak -e '/match/,+2d' someCommonName.txt

But deleting the match, two lines after it and two lines before it does not work?

sed -i.bak -e '/match/-2,+2d' someCommonName.txt
sed: -e expression #1 unknown command: `-'

Why is that?

Upvotes: 3

Views: 2725

Answers (4)

Ed Morton
Ed Morton

Reputation: 204099

FWIW this is how I'd really do the job (just change the b and a values to delete different numbers of lines before/after match is found):

$ cat file
1
2
3
4
5 match
6
7
8
9

$ awk -v b=2 -v a=2 'NR==FNR{if (/match/) for (i=(NR-b);i<=(NR+a);i++) skip[i]; next } !(FNR in skip)' file file
1
2
8
9

$ awk -v b=3 -v a=1 'NR==FNR{if (/match/) for (i=(NR-b);i<=(NR+a);i++) skip[i]; next } !(FNR in skip)' file file
1
7
8
9

Note that the above assumes that when 2 "match"s appear within a removal window you want to base the deletions on the original occurrence, not what would happen after the first match being found causes the 2nd match to be deleted:

$ cat file2
1
2
3
4 match
5
6 match
7
8
9

$ awk -v b=2 -v a=2 'NR==FNR{if (/match/) for (i=(NR-b);i<=(NR+a);i++) skip[i]; next } !(FNR in skip)' file2 file2
1
9

as opposed to the output being:

1
7
8
9

since deleting the 2 lines after the first match would delete the 2nd match and so the 2 lines after THAT would not be deleted since they no longer are within 2 lines after a match.

Something else to consider:

$ diff --changed-group-format='%<' --unchanged-group-format='' file <(grep -A2 -B2 match file)
1
2
8
9

$ diff --changed-group-format='%<' --unchanged-group-format='' file2 <(grep -A2 -B2 match file2)
1
9

That uses bash and GNU diff 3.2, idk if/which other shells/diffs would support those constructs/options.

Upvotes: 1

NeronLeVelu
NeronLeVelu

Reputation: 10039

sed -i .bak '/match/,-2 {/match/!d;};/match/,+2d' YourFile

try this (cannot test here, -2 is not available in my sed version)

Upvotes: 3

Dark Falcon
Dark Falcon

Reputation: 44191

sed operates on a range of addresses. That means either one or two expressions, not three.

/match/ is an address which matches a regex.

-2 is an address which specifies two lines before

+2 is an address which specifies two lines after

Therefore:

/match/,-2 is a range which specifies the line matching match to two lines before.

/match/-2,+2d, on the other hand, includes three addresses, and thus makes no sense.

To delete two lines before and after a pattern, I would recommend something like this (modified from this answer):

sed -n "1N;2N;/\npattern$/{N;N;d};P;N;D"

This keeps 3 lines in the buffer and reads through the file. When the pattern is found in the last line, it reads two more lines and deletes all 5. Note that this will not work if the pattern is in the first two lines of the file, but it is a start.

Upvotes: 4

Aaron Digulla
Aaron Digulla

Reputation: 328754

I don't have a complete solution but an outline: sed is a pretty simple tool which doesn't do two things at once. My approach would be to run sed once deleting the two lines after the pattern but keeping the pattern itself. The result can then be piped to sed again to remove the pattern and the two lines before.

Upvotes: 3

Related Questions