excluding first and last lines from sed /START/,/END/
Solution 1
This should do the trick:
sed -e '/=sec1=/,/=sec2=/ { /=sec1=/b; /=sec2=/b; s/^/#/ }' < input
This matches between sec1 and sec2 inclusively and then just skips the first and last line with the b
command. This leaves the desired lines between sec1 and sec2 (exclusive), and the s
command adds the comment sign.
Unfortunately, you do need to repeat the regexps for matching the delimiters. As far as I know there's no better way to do this. At least you can keep the regexps clean, even though they're used twice.
This is adapted from the SED FAQ: How do I address all the lines between RE1 and RE2, excluding the lines themselves?
Solution 2
If you're not interested in lines outside of the range, but just want the non-inclusive variant of the Iowa/Montana example from the question (which is what brought me here), you can write the "except for the first and last matching lines" clause easily enough with a second sed:
sed -n '/PATTERN1/,/PATTERN2/p' < input | sed '1d;$d'
Personally, I find this slightly clearer (albeit slower on large files) than the equivalent
sed -n '1,/PATTERN1/d;/PATTERN2/q;p' < input
Solution 3
Another way would be
sed '/begin/,/end/ {
/begin/n
/end/ !p
}'
/begin/n
-> skip over the line that has the "begin" pattern
/end/ !p
-> print all lines that don't have the "end" pattern
Taken from Bruce Barnett's sed tutorial http://www.grymoire.com/Unix/Sed.html#toc-uh-35a
Solution 4
I've used:
sed '/begin/,/end/{/begin\|end/!p}'
This will search all the lines between the patterns, then print everything not containing the patterns
Solution 5
you could also use awk
awk '/sec1/{f=1;print;next}f && !/sec2/{ $0="#"$0}/sec2/{f=0}1' file
Related videos on Youtube
Chen Levy
Self motivated, autodidact, diligent documenter and a mentor. For as long as I can remember, I always was fascinated by technology. I am a long time #Python and #Linux developer, with experience in #Rust. Working with #Open Source technologies and contributing back. Over the years I filled roles in #systems, #backend and #devops in #storage and #security companies. Worked with #AWS, #Bash, #Docker, #ELK, #Flask, #Git, #PKI, #SQL and much more. I am an #autodidact. Constantly learning new techniques and technologies (such as #async/await, #FastAPI, #Haskell, etc). I also tend to disseminate knowledge: Diligent documentation writer, an experienced and well received instructor, both #mentoring one-on-one and as a public speaker. This is one of the reasons I consider myself one of the lucky few for whom their job is also their hobby and passion. Happiest when coding using Emacs. Successfully completed projects I wrote from scratch as well as took ownership and maintained legacy code. Consumed and designed #APIs (#RESTful and otherwise). I also worked with Networking (#TCP/IP) I am not a stranger to reading RFCs. Done development support work with dynamic languages (#Python, #Perl) and shell scripting (#Bash), created build and deployment systems (#CMake, GNU build tools), designed #CI/CD pipelines (#GitLab-CI, #Jenkins). A long time ago in a galaxy far away I also done some low level development with C/C++ and code migration, writing in both the Linux kernel and user space. Now a days prefer Rust for low level tasks.
Updated on August 16, 2020Comments
-
Chen Levy almost 4 years
Consider the input:
=sec1= some-line some-other-line foo bar=baz =sec2= c=baz
If I wish to process only =sec1= I can for example comment out the section by:
sed -e '/=sec1=/,/=[a-z]*=/s:^:#:' < input
... well, almost.
This will comment the lines including "=sec1=" and "=sec2=" lines, and the result will be something like:
#=sec1= #some-line #some-other-line # #foo #bar=baz # #=sec2= c=baz
My question is: What is the easiest way to exclude the start and end lines from a /START/,/END/ range in sed?
I know that for many cases refinement of the "s:::" claws can give solution in this specific case, but I am after the generic solution here.
In "Sed - An Introduction and Tutorial" Bruce Barnett writes: "I will show you later how to restrict a command up to, but not including the line containing the specified pattern.", but I was not able to find where he actually show this.
In the "USEFUL ONE-LINE SCRIPTS FOR SED" Compiled by Eric Pement, I could find only the inclusive example:
# print section of file between two regular expressions (inclusive) sed -n '/Iowa/,/Montana/p' # case sensitive
-
Chen Levy almost 15 yearsYes, this exactly what I was looking for. Thanks.
-
orolo over 11 yearsnice. also, the second version doesn't blow up php because of that pesky $.
-
mbigras about 7 yearsFor folks on macOS with BSD sed you need to use actual newlines instead of semicolons. For more details check out this answer
-
Sundeep almost 7 yearsnot sure about other versions, but with GNU sed, this could be easily done using
'/=sec1=/,/=sec2=/ { //! s/^/#/ }'
... from manualempty regular expression ‘//’ repeats the last regular expression match
-
Dan about 6 yearsI have a hunch, they're not equivalent, should there be more than one of those ranges in the stream/file.
-
yugr over 4 years@Sundeep Given that this is the most concise expression, why not post it as answer?