Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

sed remove first pattern match only

Tags:

sed

I would like to match a set of data between two patterns and remove this data and the start/end patterns but only for the first occurrence of the pattern.

So if this is the test data:

PATTERNSTART
LINE1
LINE2
LINE3
PATTERNEND
PATTERNSTART
LINE1
LINE2
LINE3
PATTERNEND
TESTLINE1
TESTLINE2
TESTLINE3
PATTERNSTART
LINE1
LINE2
LINE3
PATTERNEND

This will quite happy remove all the pattern matches and the lines in between but I only want to remove the first pattern match and the lines in between:

sed '/PATTERNSTART/,/PATTERNEND/d' testsed.txt

Output:

TESTLINE1
TESTLINE2
TESTLINE3

Required output:

PATTERNSTART
LINE1
LINE2
LINE3
PATTERNEND
TESTLINE1
TESTLINE2
TESTLINE3
PATTERNSTART
LINE1
LINE2
LINE3
PATTERNEND

Any sed ideas?

like image 569
SnazzyBootMan Avatar asked Feb 11 '23 18:02

SnazzyBootMan


1 Answers

It's a bit incredible-machiney, but this works:

sed '/PATTERNSTART/,/PATTERNEND/ { // { x; s/$/./; x; }; x; /.../! { x; d; }; x; }' filename

as follows:

/PATTERNSTART/,/PATTERNEND/ {   # in the pattern range
  // {                          # in the first and last line:
    x
    s/$/./                      # increment a counter in the hold buffer by
                                # appending a character to it. The counter is
                                # the number of characters in the hold buffer.
    x
  }
  x                             # for all lines in the range: inspect the
                                # counter
  /.../! {                      # if it is not three or more (the counter
                                # becomes three with the start line of the
                                # second matching range)
    x
    d                           # delete the line
  }
  x
}

The xs in that code are largely to ensure that the counter ends up back in the hold buffer when the whole thing is over. The // bit works because // repeats the last attempted regex, which is the start pattern of the range for its first line and the end pattern for the others.

like image 132
Wintermute Avatar answered Feb 19 '23 10:02

Wintermute