skip to Main Content

I have a text file file.txt with the content:

lord
blue
bird
The sky
reptile
lorwood
wood

I’m trying to print the lines between "lord" and "reptile" using command sed and Basic Regular Expression as:

$ sed -n '/^lor/,/^rep/p' file.txt

However, it prints the whole file, like a cat. Why?

The version of sed I’m using is:

$ sed --version
sed (GNU sed) 4.8
Packaged by Debian
Copyright (C) 2020 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <https://gnu.org/licenses/gpl.html>.
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.

Written by Jay Fenlason, Tom Lord, Ken Pizzini,
Paolo Bonzini, Jim Meyering, and Assaf Gordon.

This sed program was built with SELinux support.
SELinux is disabled on this system.

GNU sed home page: <https://www.gnu.org/software/sed/>.
General help using GNU software: <https://www.gnu.org/gethelp/>.
E-mail bug reports to: <[email protected]>.

2

Answers


  1. You have a second lor line immediately after the rep line so sed is printing from lord to reptile and then from lorwood til the end of the file as 2 separate blocks which together encompass all of the lines from your input.

    You can see the 2 separate blocks if you use awk and a flag instead of sed and a range expression:

    $ awk '/^lor/{ print "{"; f=1 } f{ print; if (/^rep/) { print "}"; f=0 } } END{if (f) print "}"}' file.txt
    {
    lord
    blue
    bird
    The sky
    reptile
    }
    {
    lorwood
    wood
    }
    

    or, if you prefer:

    $ awk '/^lor/{ ++blockNr; lineNr=1 } lineNr{ print "block="blockNr, "line="lineNr++, $0; if (/^rep/) lineNr=0 }' file.txt
    block=1 line=1 lord
    block=1 line=2 blue
    block=1 line=3 bird
    block=1 line=4 The sky
    block=1 line=5 reptile
    block=2 line=1 lorwood
    block=2 line=2 wood
    

    FWIW, I wouldn’t use a range expression /start/,/end/ (and so wouldn’t use sed) for this as it’s too hard to control the output, I’d use awk and a flag instead, see Is a /start/,/end/ range expression ever useful in awk?.

    Login or Signup to reply.
  2. This might work for you (GNU sed):

    sed -n '/lor/{:a;N;/rep/!ba;p}' file
    

    This is essentially a filter operation so use the -n command line option to suppress the implicit printing of each line.

    Match lor and using a loop, gather up future lines until the collection contains rep, then print the collection and repeat.

    N.B. Only a valid collection will be printed out by the p command, once the loop is ended.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search