3

I'm trying to delete a range using sed. The range is from a known match and the next 2 lines. Let's say I want to delete all lines that start with Don't and then the 2 lines that follow.

Please note that I am also doing substitutions in a sed command file. As such, I am avoiding using -n and /p in my solution space.

For whatever reason, I want to limit myself to one invocation of sed.

Here's my data (data.txt):

Print Me
Please Output This line
Don't Print Me and 2 more lines
This line is no good
So is this one
We should see this line
And this one, too.

Here's my expected output:

Print Me
Please Output This line
We should see this line
And this one, too.

Here's an attempted go at this:

sed -f delete_dont_plus_2.sed data.txt

With this as delete_dont_plus_2.sed:

/^Don't/,+2d

Here is my result:

sed: 1: delete_dont_plus_2.sed: expected context address

I've also tried these:

/^Don't/,/^Don't/+2d
/^Don't/,{/^Don't/+2}d

Second approach to this question:

Let's say we wanted to make this code a little more robust. Today there are 2 more lines that need to be deleted, but who knows how many lines there will be in the future. Let's say we want to delete up to, but not including We should see this line. In this variant of the question, the results are exactly the same. Again, let's consider a limited BSD sed so we cannot use an expression like /^Don't/,/^We should see this line/-1d.

Thanks!

oguz ismail
  • 1
  • 16
  • 47
  • 69
Mark
  • 4,249
  • 1
  • 18
  • 27

3 Answers3

5

You're probably using a sed that doesn't support adresses in regexp,+n form. Here is a workaround for this particular case:

/^Don't/{N;N;d;}

It simply reads two more lines into the pattern space when ^Don't is found and deletes them altogether.

But anyways, I think sed is not the right tool for this, you should use instead. E.g:

awk '/^Don\047t/{c=2;next} !(c&&c--)' file

c.f: Printing with sed or awk a line following a matching pattern


wrt

Let's say we want to delete up to, but not including We should see this line. In this variant of the question, the results are exactly the same.

Using sed you'd need to write same RE twice:

/^Don't/,/^We should see this line/{/^We should see this line/!d;}

Using awk you don't even need REs:

awk 'index($0,"Don\047t")==1{d=1} $0=="We should see this line"{d=0} !d' file
oguz ismail
  • 1
  • 16
  • 47
  • 69
  • 1
    Works for me. I had to add a little MAC fun to it: `/^Don't/{N;N;d;}` ( that is, the last semi ). I also appreciate the awk answer. Awk is my preferred tool nearly always (when compared to sed). However, I have a large sed command file already with mostly substitutions so I'm constrained. Thanks for your help – Mark May 10 '19 at 15:48
  • 1
    I hear ya, but can't speak for all other mac users in my community. In a sense, I'm stuck with the lowest common denominator. Thanks again for your help. As an additional question, how would the script change if we didn't know how many lines to delete. Rather, we wanted to delete up to, but not including the first line that started like this '/^We should see this line/'. With this variant of the question, the output should be the same. – Mark May 10 '19 at 16:10
  • 2
    for awk, see also: https://stackoverflow.com/questions/17908555/printing-with-sed-or-awk-a-line-following-a-matching-pattern – Sundeep May 10 '19 at 16:23
  • 1
    This solution may not work when the regexp is the last or second from last line as the `N` instruction will try to read past the end of the file and fail, printing what is in the pattern space. Perhaps `sed '/^Don't/{$!N;$!N;d;}' file` would prevent this. – potong May 12 '19 at 09:55
1

With GNU sed:

sed "/^Don't/,+2d" file

Output:

Print Me
Please Output This line
We should see this line
And this one, too.
Cyrus
  • 84,225
  • 14
  • 89
  • 153
0

This might work for you (GNU sed):

sed '/^Don'\''t/{s/.*/X/;h;d};x;/X/!{x;b};s/^/X/;/^XXX/z;x;d' file

This solution keeps a count from the time the regexp is encounterd.

N.B. If one of the two lines following the regexp is also the regexp, the count is restarted.

A solution less GNU specific and programmatic:

sed '/^Don'\''t/{s/.*/X/;h;d};x;/X/!{x;b};s/^/X/;/^XX\{2\}/s/.*//;x;d' file
potong
  • 55,640
  • 6
  • 51
  • 83