16

Ok

I know that this is trivial question but: How can i remove lines from files that are between two known patterns/words:

pattern1
garbage
pattern2

to obtain:

pattern1
pattern2

And does anyone known good(simple written!) resources for studying sed?? With many clear examples?

kasper
  • 641
  • 2
  • 8
  • 18
  • Possible duplicate of [Using sed to delete all lines between two matching patterns](https://stackoverflow.com/q/6287755/608639), [SED delete lines between two pattern matches](https://stackoverflow.com/q/8085633/608639), [sed delete lines between two patterns, without the second pattern, including the first pattern](https://stackoverflow.com/q/42898905/608639), [SED delete specific lines between two patterns?](https://stackoverflow.com/q/19233578/608639) and friends. – jww Dec 23 '19 at 17:44

6 Answers6

20
sed -n '/pattern1/{p; :a; N; /pattern2/!ba; s/.*\n//}; p' inputfile

Explanation:

/pattern1/{         # if pattern1 is found
    p               # print it
    :a              # loop
        N           # and accumulate lines
    /pattern2/!ba   # until pattern2 is found
    s/.*\n//        # delete the part before pattern2
}
p                   # print the line (it's either pattern2 or it's outside the block)

Edit:

Some versions of sed have to be spoon-fed:

sed -n -e '/pattern1/{' -e 'p' -e ':a' -e 'N' -e '/pattern2/!ba' -e 's/.*\n//' -e '}' -e 'p' inputfile
Dennis Williamson
  • 346,391
  • 90
  • 374
  • 439
  • it gives me `sed: -e expression #1, char 58: Unknown option to 's'`. My sed version is 3.02 – kasper Feb 22 '11 at 00:47
  • @Dennis: Oh, version from edit is doing the right thing. Thanks once more ! – kasper Feb 22 '11 at 01:15
  • 4
    Or with less black magic `sed '/pattern1/,/pattern2/{/pattern1/b;/pattern2/b;d}' inputfile` :) –  Feb 22 '11 at 13:23
  • @pooh: Your first one doesn't work with this test data (lines with "xxx" should not be printed, everything else should): `echo -e 'aaa\npattern1\ncccxxx\ndddxxx \npattern2\nfff\nggg\npattern1\nAAAxxx\nBBBxxx \nCCCxxx\nDDDxxx\npattern2\nEEE\nFFF'` – Dennis Williamson Feb 22 '11 at 14:38
  • @Dennis Williamson: Ah, true:) Tested on one line contents! –  Feb 22 '11 at 15:22
  • @DennisWilliamson: I tried your test data with pooh's suggestion and it worked fine (on OSX, maybe that's why?). Why does it fail, or why should it? – jakesandlund Mar 30 '12 at 00:14
  • @jakesandlund: pooh's `sed` command in the comment from Feb 22 '11 at 13:23 *does* work with my test data from my comment from Feb 22 '11 at 14:38. You'll note that my comment refers to "[pooh's] first one". There is only one at this point, and I can't remember if there was another that may now be deleted, but that phrase would seem to imply so. Pooh's leading "Or" would seem to also imply that (or it could refer to the "black magic" in my answer). In any case, pooh's extant version is perfectly fine and is quite a bit more straightforward than mine. – Dennis Williamson Mar 30 '12 at 00:38
  • Any of those solution does work when pattern1==pattern2 but solution proposed by user332325 works in that case – Clement Dec 14 '22 at 08:22
17

This will work for both GNU and BSD sed:

sed '/pattern1/,/pattern2/{//!d;}' file
t7e
  • 322
  • 1
  • 3
  • 9
potong
  • 55,640
  • 6
  • 51
  • 83
  • 6
    If anybody else uses this with BSD `sed` (i.e. Mac OSX), and you get an error `extra characters at the end of d command`, simply add `;` after the `d` like this: `sed '/pattern1/,/pattern2/{//!d;}' file` – rkd Dec 05 '16 at 22:10
  • 2
    how do you do this inclusive of the patterns? – qodeninja Dec 30 '17 at 01:50
5

This is easily done with awk:

BEGIN { doPrint = 1; }
/pattern1/ { doPrint = 0; print $0; }
/pattern2/ { doPrint = 1; }
{ if (doPrint) print $0; }

I've found the sed info is fairly easy reading, with many examples. Same thing for awk.

Daniel Gallagher
  • 6,915
  • 25
  • 31
4
awk '/pattern1/{g=1;next}/pattern2/{g=0;next}g' file
kurumi
  • 25,121
  • 5
  • 44
  • 52
2

This sed code will work as well:

sed '/PATTERN1/,/PATTERN2/d' FILE
Inder
  • 3,711
  • 9
  • 27
  • 42
  • Although not as OP wanted, this works well as the *inclusive* version of the answer by @potong – Sadi Aug 19 '22 at 13:53
0

You may also use the Unix text editor ed:

echo '
pattern1
garbage
pattern2
' > test.txt

cat <<-'EOF' | sed -e 's/^ *//' -e 's/ *$//' | ed -s test.txt &>/dev/null
  H
  /pattern1/+1,/pattern2/-1d
  wq
EOF

For more information see: Editing files with the ed text editor from scripts

tylo
  • 1