This article is part of the article series "Sed One-Liners Explained."
<- previous article next article ->

sed -- the superman of unix stream editingThis is the third and final part of an article on the famous sed one-liners. This part will explain sed one-liners for selective deletion of certain lines and special applications of sed. See part one for introduction of the series.

Similarly to famous Awk one-liners, sed one-liners are short and concise sed programs that span less than one terminal line. They were written by Eric Pement and are floating around on the Internet as 'sed1line.txt' file.

If you are intrigued by this article series, I suggest that you subscribe to my posts!

Update: Spanish translation of part three is available!

Eric's sed one-liners are divided into several sections:

Grab my "sed cheat sheet" and a local copy of sed1line.txt file, and let the explanation begin!

Awesome news: I have written an e-book based on this article series. Check it out:

5. Selective Deletion of Certain Lines

68. Print all lines in the file except a section between two regular expressions.

sed '/Iowa/,/Montana/d'

This one-liner continues where the previous left off. One-liner #67 used the range match "/start/,/finish/" to print lines between two regular expressions (inclusive). This one-liner, on the other hand, deletes lines between two regular expressions and prints all the lines outside this range. Just to remind you, a range "/start/,/finish/" matches all lines starting from the first line that matches a regular expression "/start/" to the first line that matches a regular expression "/finish/". In this particular one-liner the "d", delete, command is applied to these lines. The delete command prevents the matching lines from ever seeing the light.

For example, suppose your input to this one-liner was:

Florida
<strong>Iowa
New York
San Jose
Montana</strong>
Texas
Fairbanks

Then after the sed program has finished running, the output is:

Florida
Texas
Fairbanks

We see this output because the lines from Iowa to Montana matched the "/Iowa/,/Montana/" range match (i put the matched lines in bold) and were deleted.

69. Delete duplicate, consecutive lines from a file (emulates "uniq").

sed '$!N; /^\(.*\)\n\1$/!P; D'

This one-liner acts as the "uniq" Unix utility. So how does it work? First of all, for every line that is not the very last line of input, sed appends the next line to the pattern space by the "N" command. The "N" command is restricted to all but the last line by "$!" restriction pattern. The newly appended line is separated from the previous line by the "\n" character. Next, the pattern space is matched against "/^\(.*\)\n\1$/" regular expression. This regular expression captures the previous line up to "\n" character and saves it in the match group "\1". Then it tests if the newly appended line is the same as the previous one. If it is not, the "P" gets executed. If it is, the "P" command does not get executed. The "P" command prints everything in the pattern space up to the first "\n" character. Next the "D" command executes and deletes everything up to the first "\n" char, leaving only the newly read line in pattern space. It also forces the sed script to begin from the first command.

This way it loops over all lines, comparing two consecutive lines. If they are equal, the first line gets deleted, and a new line gets appended to what's left. If they are not equal, the first one gets deleted, and deleted.

I think it's hard to understand what is going on from this description. I'll illustrate it with an example. Suppose this is the input:

foo
foo
foo
bar
bar
baz

The first thing sed does is it reads the first line of input in pattern space. The pattern space now contains "foo". Now the "N" command executed. The pattern space now contains "foo\nfoo". Next the pattern space is tested against "/^\(.*\)\n\1$/" regular expression. This regular expression matches because "\(.*\)" is "foo" and "/^\(.*\)\n\1$/" is "foo\nfoo", exactly what we have in the pattern space. As it matched, the "P" command does not get executed. Now the "D" command executes, deleting the everything up to first "\n" from pattern space. The pattern space now contains just "foo". The "D" command forces sed to start from the first command. Now the "N" is executed again, the pattern space now contains "foo\nfoo" again and the same thing happens, "P" does not get executed and "D" deletes the first "foo", leaving the pattern space with just "foo" in it. Now the "N" gets executed once again, this time "bar" gets appended to pattern space. It contains "foo\nbar" now. The regular expression "/^\(.*\)\n\1$/" does not match and "P" gets executed, printing "foo". After that "D" gets executed wiping "foo" from pattern space. The pattern space now contains "bar". The commands restart and "N" gets executed, it appends the next "bar" to current pattern space. Now it contains "bar\nbar". Just like with "foo\nfoo", nothing gets printed, and "D" deletes the first "bar", leaving pattern space with "bar". The one-liner restarts its execution. Now "N" reads in the final line "baz". The pattern space contains "bar\nbaz" which does not match the regular expression. The "P" prints out the "bar" and "D" deletes "bar". Now "N" does not get executed because we are at the last line of input. The "$!N" restricts "N" to all lines but last. At this moment pattern space contains only the last "baz", the regular expression does not match, so "baz" gets printed. The "D" command executes, emptying the pattern space. There is no more input and sed quits.

The output for this example is:

foo
bar
baz

I think this is one of the most detailed explanations I have written about a single one liner. :)

70. Delete duplicate, nonconsecutive lines from a file.

sed -n 'G; s/\n/&&/; /^\([ -~]*\n\).*\n\1/d; s/\n//; h; P'

This is a very tricky one-liner. It stores the unique lines in hold buffer and at each newly read line, tests if the new line already is in the hold buffer. If it is, then the new line is purged. If it's not, then it's saved in hold buffer for future tests and printed.

A more detailed description - at each line this one-liner appends the contents of hold buffer to pattern space with "G" command. The appended string gets separated from the existing contents of pattern space by "\n" character. Next, a substitution is made to that substitutes the "\n" character with two "\n\n". The substitute command "s/\n/&&/" does that. The "&" means the matched string. As the matched string was "\n", then "&&" is two copies of it "\n\n". Next, a test "/^\([ -~]*\n\).*\n\1/" is done to see if the contents of group capture group 1 is repeated. The capture group 1 is all the characters from space " " to "~" (which include all printable chars). The "[ -~]*" matches that. Replacing one "\n" with two was the key idea here. As "\([ -~]*\n\)" is greedy (matches as much as possible), the double newline makes sure that it matches as little text as possible. If the test is successful, the current input line was already seen and "d" purges the whole pattern space and starts script execution from the beginning. If the test was not successful, the doubled "\n\n" gets replaced with a single "\n" by "s/\n//" command. Then "h" copies the whole string to hold buffer, and "P" prints the new line.

71. Delete all lines except duplicate consecutive lines (emulates "uniq -d").

sed '$!N; s/^\(.*\)\n\1$/\1/; t; D'

This sed one-liner prints only the duplicate lines. This sed one-liner starts with reading in the next line from input with the "N" command. As I already mentioned, the current line and the next get separated by "\n" character after "N" executes. This one-liner also restrics "N" to all lines but last with "$!" restriction. Now a substitution "s/^\(.*\)\n\1$/\1/" is tried. Similarly to one-liner #69, this substitution replaces two repeating strings with one. For example, a string "foo\nfoo" gets replaced with just "foo". Now, if this substitution was successful (there was a repeated string), the "t" command takes the script to the end where the current pattern space gets printed automatically. If the substitution was not successful, "D" executes, deleting the non-repeated string. The cycle continues and this way only the duplicate lines get printed once.

Let's take a look at an example. Suppose the input is:

foo
foo
bar
baz

This one-liner reads the first line and immediately executes the "N" command. The pattern space now is "foo\nfoo". The substitution "s/^\(.*\)\n\1$/\1/" is tried and it's successful, because "foo" is repeated twice. The pattern space now contains just a single "foo". As the substitution was successful, "t" command branches to the end of the script. At this moment "foo" gets printed. Now the cycle repeats. Sed reads in "bar", the "N" command appends "baz" to "bar". The pattern space now is "bar\nbaz". The substitution is tried, but it's not successful, as "bar" is not repeated. As the substitution failed, "t" does nothing and "D" executes, deleting "bar" from pattern space. The pattern space is left with single "baz". Command "N" no longer executes as we reached end of file, substitution fails, "t" fails, and "D" deletes the "baz".

The end result is:

foo

Just as we expected - only the duplicate line got printed.

72. Delete the first 10 lines of a file.

sed '1,10d'

This one-liner restricts the "d" command to a range of lines by number. The "1,10" means a range matching lines 1 to 10 inclusive. On each of the lines the "d" command gets executed. It deletes the current pattern space, and restarts the commands from beginning. The default action for lines > 10 is to print the line.

73. Delete the last line of a file.

sed '$d'

This one-liner restricts the "d" command to the last line of file. It's done by specifying the special char "$" as the line to match. It matches only the last line. The last line gets deleted, but the others get printed implicitly.

74. Delete the last 2 lines of a file.

sed 'N;$!P;$!D;$d'

This one-liner always keeps two lines in the pattern space. At the very last line, it just does not output these last two. All the others before last two get output implicitly. Let's see how it does it. As soon as sed reads the first line of input in pattern space, it executes the first command "N". It places the 2nd line of input in pattern space. The next two commands "$!P" and "$!D" print the first part of pattern space up to newline character, and delete this part from pattern space. They keep doing it until the very last line gets appended to pattern space by "N" command. At this moment the last two lines are in pattern space and "$d" executes, deleting them both. That's it. Last two lines got deleted.

If there is just one line of data, then it outputs it.

75. Delete the last 10 lines of a file.

sed -e :a -e '$d;N;2,10ba' -e 'P;D'

This is really straight forward one-liner. It always keeps 10 lines in pattern-space, by appending each new input line with "N", and deleting the 11th excessive line with "D". Once the end of file is reached, it "d" the whole pattern space, deleting the last 10 lines.

sed -n -e :a -e '1,10!{P;N;D;};N;ba'

This is also a straight forward one-liner. For the lines that are not 1-10, it appends them to pattern space with "N". For lines > 10, it prints the first line in pattern space with "P", appends another line with "N" and deletes the printed line with "D". The "D" command causes sed to branch to the beginning of script! The "N;ba" at the end never, ever gets executed again for lines > 10. It keeps looping this way "P", "N", "D", always keeping 10 lines in pattern space and printing line-10 on each cycle. The "N" command causes script to quit if it tries to read past end of file.

76. Delete every 8th line.

gsed '0~8d'

This one-liner only works with GNU Sed only. It uses a special address range match "first~step" that matches every step'th line starting with the first. In this one-liner first is 0 and step is 8. Zero is not a valid physical line number, so the very first line of input does not match. The first line to match is 8th, then 16th, then 24th, etc. Each line that matches is deleted by "d" command.

sed 'n;n;n;n;n;n;n;d;'

This is a portable version. The "n" command prints the current pattern space, empties it, and reads in the next line. It does so for every 7 lines, and 8th line gets deleted with "d". This process continues until all input has been processed.

77. Delete lines that match regular expression pattern.

sed '/pattern/d'

This one-liner executes the "d" command on all lines that match "/pattern/". The "d" command deletes the line and skips to the next line.

78. Delete all blank lines in a file (emulates "grep '.'".

sed '/^$/d'

The regular expression "/^$/" in this one-liner tests if the beginning of line matches the end of the line. Only the empty lines have this property and sed deletes them.

Another way to do the same is:

sed '/./!d'

This one-liner tests if the line matches at least one character. The dot "." in the regular expression matches any character. An empty line does not have any characters and it does not match this regular expression. Sed deletes all the lines that do not match this regular expression.

79. Delete all consecutive blank lines from a file (emulates "cat -s").

sed '/./,/^$/!d'

This one-liner leaves one blank line at the end of the file, if there are multiple blanks at the end. Other than that, all consecutive blanks are stripped.

It uses an inverse range match "/start/,/finish/!" to "d" delete lines from first blank line, to first non-blank, non-inclusive.

sed '/^$/N;/\n$/D'

This one-liner leaves one blank line at the beginning and end of the file, if there are multiple blanks at both sides. Other than that, all consecutive blanks are stripped.

The consecutive empty lines get appended in pattern space by "/^$/N" command. The "/\n$/D" command matches and deletes blanks until only 1 is left. At that moment it no longer matches, and the line is output.

80. Delete all consecutive blank lines from a file except the first two.

sed '/^$/N;/\n$/N;//D'

In case of > 2 blank lines, this one-liner trims them down to two. There is a catch to this one-liner. Let me explain it first. See the last command "//D"? It's a shortcut for "/previous-match/D". In this case it's shortcut for "/\n$/D". Alright, now the one-liner itself. On every empty line, it appends the next to current pattern space with "/^$/N" command. Next it tests if the line just read in was actually a blank line with "/\n$/", if it is, it reads another line in with "N". At this moment it repeats the same test "/\n$/". If the line was a blank one again, it deletes the first blank line and restarts sed script from the beginning. Notice that at all times only 2 consecutive blank lines are in pattern space. This way any number of blank lines get deleted and only two are left.

81. Delete all leading blank lines at the top of a file.

sed '/./,$!d'

This one-liner inverts a match "match from the first non-blank line to end of file". It becomes "match from the beginning of file to last blank line".

82. Delete all trailing blank lines at the end of a file.

sed -e :a -e '/^\n*$/{$d;N;ba' -e '}'

This one-liner accumulates blank lines in pattern space until it either hits end or hits a non-blank line. If it hits end, "$d" deletes the whole pattern space (which contained just the trailing blank lines) and quits. If however, it hits non-blank line, the whole pattern space gets printed implicitly and script continues as if nothing had happened.

This one is a portable version.

gsed -e :a -e '/^\n*$/N;/\n$/ba'

This is the same script, except a shorter version, made to work with Gnu Sed.

83. Delete the last line of each paragraph.

sed -n '/^$/{p;h;};/./{x;/./p;}'

This one-liner always keeps the previous line in hold buffer. It's accomplished by 2nd block of commands "/./{x;/./p;}". In this block, the pattern space (1 line) gets exchanged with hold buffer (1 line) by "x" command and if the hold buffer was not empty, it gets printed by "p". The next moment to note is what happens on the first empty line. That is the line after the paragraph. At this moment "/^$/{p;h;}" gets executed, that prints the blank line (but does not print the last line of paragraph!), and puts the blank line in hold buffer. Once a new paragraph is reached, the script executed just like it was the very first paragraph of the input.

6. Special Sed Applications

84. Remove nroff overstrikes.

Nroff overstrikes are chars that are formatted to stand out in bold. They are achieved like in old typewriters, where you would do backspace and hit the same key again. In nroff it's key CHAR, CTRL+H, CHAR. This one-liner deletes the CHAR, CTRL+H, leaving just plain CHAR.

sed 's/.^H//g'

Press Ctrl+V and then Ctrl+H to insert ^H literally in sed one-liner. It then uses the substitute command to delete any char "." followed by CTRL+H "^H".

Another way to do the same is use a hex escape expression that works in most recent seds:

sed 's/.\x08//g'

Yet another way is to use "echo" and enable interpretation of backslashed characters:

sed 's/.'`echo -e "\b"`'//g'

85. Print Usenet/HTTP/Email message header.

gsed -r '/^\r?$/q'

Usenet, HTTP and Email headers are similar. They are a bunch of text lines, separated from the body of the message with two new lines "\r\n\r\n". Some implementations might even go with just "\n\n". This one-liner quits on the first line that is either empty or contains "\r". In other words, it prints the message header and quits.

86. Print Usenet/HTTP/Email message body.

sed '1,/^$/d'

This one-liner uses a range match "1,/^$/" to delete lines starting from 1st, and ending with the first blank line (inclusive). As I explained in the previous one-liner #78 above, "/^$/" matches empty lines. All the lines before first blank line in a Usenet/Email message or a HTTP header are message headers. They get deleted.

87. Extract subject from an email message.

sed '/^Subject: */!d; s///; q'

This one-liner deletes all lines that do not match "^Subject: ". Then it re-uses the match in "s///" to delete "Subject: " part from the line, leaving just the real subject. Please notice how "s///" is equivalent to "s/previous-match//", where "previous-match" is "^Subject: *" in this one-liner.

88. Extract sender information from an email message.

sed '/^From: */!d; s///; q'

This one liner is equivalent to the previous one, except it prints sender information from email.

89. Extract email address from a "Name Surname <email@domain.com>" string.

sed 's/.*< *//;s/ *>.*//;

This one-liner strips all symbols before < symbol (and any whitespace after it), and stips all symbols after > symbol (including whitespace before it). That's it. What's left is email@domain.com.

90. Add a leading angle bracket and space to each line (quote an email message).

sed 's/^/> /'

This one-liner substitutes zero-width anchor "^" that matches beginning of line with "> ". As it's a zero-width anchor, the result is that "> " gets added to beginning of each line.

91. Delete leading angle bracket from each line (unquote an email message).

sed 's/^> //'

It does what it says, deletes two characters ">" and a space " " from the beginning of each line.

92. Strip HTML tags.

sed -e :a -e 's/<[^>]*>//g;/</N;//ba'

Sed is not made for parsing HTML. This is a very crude version of HTML tag eraser. It starts by creating a branch label named "a". Then on each line it substitutes "<[^>]*>" with nothing as many times as possible ("g" flag for s/// command). The "<[^>]*>" expression means match match symbol "<" followed by any other symbols that are not ">", and that ends with ">". This is a common pattern in regular expressions for non-greediness. Next, the one-liner tests if there are any open tags left on the line, if there are "N" reads the next line of input to make it work across multiple lines. "//ba" finally branches to the beginning of the script (it's short for "/previous-expression/ba" which in this case is "/</ba").

Sed One-Liners Explained E-Book

I have written an e-book called "Sed One-Liners Explained". I improved the explanations of the one-liners in this article series, added new one-liners and added three new chapters - an introduction to sed, a summary of sed addresses and ranges, and debugging sed scripts with sed-sed. Please take a look:

Have Fun!

This post completes the three part article on the superman of Unix stream editing. I hope that you learned a thing or two and it was my pleasure explaining them.

Just as with the three part article on famous Awk one-liners explained, my plans are to create a 'sed1line-explained.txt' file that will be supplementary to 'sed1line.txt', and publish an ebook in pdf format.

If you have any comments on the one-liners, please let me know in the comments. Thanks!

Save Time by Speeding Up VideosThis is going to be a small, technical tutorial on how to save a lot of time by watching videos at higher playback rates.

I first read about this idea from my most favorite personal development blog at Steve Pavlina.com. In his post "Overclock Your Audio Learning" he says that he occasionally listens to audios at 4.1x. At this speed 4 hour video/audio can be listened in less 1 hour!

I personally found it impossible to understand anything at 4x speed. My optimal listening speed is 1.65x - 2.1x.

To speed up the videos you will first need to download and install AviSynth. AviSynth is kind of a video programming language with which you can do all kinds of manipulations to videos programmatically. If you are on Windows, then during the installation make sure to associate .avs file extension with Windows Media Player and not Notepad.

Next, create this AviSynth script, and place it in the same directory as your video. Name the script as "speedup.avs" or something similar. Make sure the extension is ".avs" if you are on Windows!

file = "file_name_of_video.avi"
speedup = 1.65
pitch = 100

DirectShowSource(file)

audio_rate = last.audiorate
video_rate = last.framerate

AssumeSampleRate(int(audio_rate*speedup))
AssumeFPS(video_rate*speedup)
TimeStretch(pitch = pitch)

There are three variables that you can change in this simple script. The first is "file". It should be the filename of the video you are about to watch. The next is "speedup". It's the new playback rate, you may set it to any value you wish. For example, if you set it to 2.0, then the video will play twice as fast as it normally would. And the last parameter to change is the "pitch". You may change it to something lower than 100 when the video plays at higher speeds to make the speaker sound lower. I usually keep "speedup" at 1.65 and "pitch" at 75.

Once you have made your own configuration, just double click the .avs on Windows to play it at the new playback speed, or play it through mplayer on Linux!

Update: My blog readers bobb and crb suggested two new techniques on how to watch videos faster. Bobb suggested just to use mplayer. Turns out it already has an option to play videos faster!

mplayer -speed 1.65 file.avi

# use keys [ ], and { } to control the playback speed
# use backspace to reset video speed to normal.

Crb suggested to use MySpeed™ Plug-In for YouTube to speed up video on YouTube in real time.

Here are a few examples that I crafted at speeds 1x, 1.4x, 1.65x, 2x, 2.25x, 2.5x, 2.75x and 3x. They are from Alan Kay's keynote speech "The computer revolution hasn't happend yet" at OOPSLA Conference in 1997.

After a few minutes of listening at higher speeds, try going back to listen at 1x. It will seem incredibly slow because your mind will have adapted to the faster input rate.

Alan Kay's talk at a normal speed. Total time: 5 mins.

Direct URL: http://www.youtube.com/watch?v=MaRODiPR-ZU

Alan Kay's talk at 1.4x speed. Total time: 3:34 mins.

Direct URL: http://www.youtube.com/watch?v=Oc_3yk22gn8

Alan Kay's talk at 1.65x speed. Total time: 3 mins.

Direct URL: http://www.youtube.com/watch?v=lrAq86Qk_rU

Alan Kay's talk at 2x speed. Total time: 2:30 mins.

Direct URL: http://www.youtube.com/watch?v=WlwEq4HXB3Y

Alan Kay's talk at 2.25x speed. Total time: 2:13 mins.

Direct URL: http://www.youtube.com/watch?v=b0K5JMjtP3w

Alan Kay's talk at 2.5x speed. Total time: 2 mins.

Direct URL: http://www.youtube.com/watch?v=YBt01TFNIA0

Alan Kay's talk at 2.75x speed. Total time: 1:49 mins.

Direct URL: http://www.youtube.com/watch?v=BNCqZp0XOVw

Alan Kay's talk at 3x speed. Total time: 1:40 mins.

Direct URL: http://www.youtube.com/watch?v=8DsuyPNOqGw

Do you have any other techniques to speed up videos? I am also curious at what speeds do you feel the most comfortable watching the videos?

It would also be cool to create a hack that modifies youtube and google video players to make them play videos faster natively.

Ps. Did you know that I was a big fan of video lectures? I have been collecting math, physics, computer science video lectures for almost 3 years now and posting them to my other Free Science Online Blog.

This article is part of the article series "Awk One-Liners Explained."
<- previous article next article ->

awk programming one-liners explainedThis is the third and final part of a three-part article on the famous Awk one-liners. This part will explain Awk one-liners for selective printing and deletion of certain lines. See part one for introduction of the series.

If you just came to my website, then you might wonder, "What are these Awk one-liners and why are they famous?" The answer is very simple - they are small and beautiful Awk programs that do one and only text manipulation task very well. They have been circulating around the Internet as awk1line.txt text file and they have been written by Eric Pement.

If you are intrigued by this article series, I suggest that you subscribe to my posts, as I will have a lot more interesting and educational articles this year.

Eric Pement's Awk one-liner collection consists of five sections:

Awesome news: I have written an e-book based on this article series. Check it out:

Grab my Awk cheat sheet and the local copy of Awk one-liners file awk1line.txt and let's roll.

4. Selective Printing of Certain Lines

45. Print the first 10 lines of a file (emulates "head -10").

awk 'NR < 11'

Awk has a special variable called "NR" that stands for "Number of Lines seen so far in the current file". After reading each line, Awk increments this variable by one. So for the first line it's 1, for the second line 2, ..., etc. As I explained in the very first one-liner, every Awk program consists of a sequence of pattern-action statements "pattern { action statements }". The "action statements" part get executed only on those lines that match "pattern" (pattern evaluates to true). In this one-liner the pattern is "NR < 11" and there are no "action statements". The default action in case of missing "action statements" is to print the line as-is (it's equivalent to "{ print $0 }"). The pattern in this one-liner is an expression that tests if the current line number is less than 11. If the line number is less than 11, Awk prints the line. As soon as the line number is 11 or more, the pattern evaluates to false and Awk skips the line.

A much better way to do the same is to quit after seeing the first 10 lines (otherwise we are looping over lines > 10 and doing nothing):

awk '1; NR == 10 { exit }'

The "NR == 10 { exit }" part guarantees that as soon as the line number 10 is reached, Awk quits. For lines smaller than 10, Awk evaluates "1" that is always a true-statement. And as we just learned, true statements without the "action statements" part are equal to "{ print $0 }" that just prints the first ten lines!

46. Print the first line of a file (emulates "head -1").

awk 'NR > 1 { exit }; 1'

This one-liner is very similar to previous one. The "NR > 1" is true only for lines greater than one, so it does not get executed on the first line. On the first line only the "1", the true statement, gets executed. It makes Awk print the line and read the next line. Now the "NR" variable is 2, and "NR > 1" is true. At this moment "{ exit }" gets executed and Awk quits. That's it. Awk printed just the first line of the file.

47. Print the last 2 lines of a file (emulates "tail -2").

awk '{ y=x "\n" $0; x=$0 }; END { print y }'

Okay, so what does this one do? First of all, notice that "{y=x "\n" $0; x=$0}" action statement group is missing the pattern. When the pattern is missing, Awk executes the statement group for all lines. For the first line, it sets variable "y" to "\nline1" (because x is not yet defined). For the second line it sets variable "y" to "line1\nline2". For the third line it sets variable "y" to "line2\nline3". As you can see, for line N it sets the variable "y" to "lineN-1\nlineN". Finally, when it reaches EOF, variable "y" contains the last two lines and they get printed via "print y" statement.

Thinking about this one-liner for a second one concludes that it is very ineffective - it reads the whole file line by line just to print out the last two lines! Unfortunately there is no seek() statement in Awk, so you can't seek to the end-2 lines in the file (that's what tail does). It's recommended to use "tail -2" to print the last 2 lines of a file.

48. Print the last line of a file (emulates "tail -1").

awk 'END { print }'

This one-liner may or may not work. It relies on an assumption that the "$0" variable that contains the entire line does not get reset after the input has been exhausted. The special "END" pattern gets executed after the input has been exhausted (or "exit" called). In this one-liner the "print" statement is supposed to print "$0" at EOF, which may or may not have been reset.

It depends on your awk program's version and implementation, if it will work. Works with GNU Awk for example, but doesn't seem to work with nawk or xpg4/bin/awk.

The most compatible way to print the last line is:

awk '{ rec=$0 } END{ print rec }'

Just like the previous one-liner, it's computationally expensive to print the last line of the file this way, and "tail -1" should be the preferred way.

49. Print only the lines that match a regular expression "/regex/" (emulates "grep").

awk '/regex/'

This one-liner uses a regular expression "/regex/" as a pattern. If the current line matches the regex, it evaluates to true, and Awk prints the line (remember that missing action statement is equal to "{ print }" that prints the whole line).

50. Print only the lines that do not match a regular expression "/regex/" (emulates "grep -v").

awk '!/regex/'

Pattern matching expressions can be negated by appending "!" in front of them. If they were to evaluate to true, appending "!" in front makes them evaluate to false, and the other way around. This one-liner inverts the regex match of the previous (#49) one-liner and prints all the lines that do not match the regular expression "/regex/".

51. Print the line immediately before a line that matches "/regex/" (but not the line that matches itself).

awk '/regex/ { print x }; { x=$0 }'

This one-liner always saves the current line in the variable "x". When it reads in the next line, the previous line is still available in the "x" variable. If that line matches "/regex/", it prints out the variable x, and as a result, the previous line gets printed.

It does not work, if the first line of the file matches "/regex/", in that case, we might want to print "match on line 1", for example:

awk '/regex/ { print (x=="" ? "match on line 1" : x) }; { x=$0 }'

This one-liner tests if variable "x" contains something. The only time that x is empty is at very first line. In that case "match on line 1" gets printed. Otherwise variable "x" gets printed (that as we found out contains the previous line). Notice that this one-liner uses a ternary operator "foo?bar:baz" that is short for "if foo, then bar, else baz".

52. Print the line immediately after a line that matches "/regex/" (but not the line that matches itself).

awk '/regex/ { getline; print }'

This one-liner calls the "getline" function on all the lines that match "/regex/". This function sets $0 to the next line (and also updates NF, NR, FNR variables). The "print" statement then prints this next line. As a result, only the line after a line matching "/regex/" gets printed.

If it is the last line that matches "/regex/", then "getline" actually returns error and does not set $0. In this case the last line gets printed itself.

53. Print lines that match any of "AAA" or "BBB", or "CCC".

awk '/AAA|BBB|CCC/'

This one-liner uses a feature of extended regular expressions that support the | or alternation meta-character. This meta-character separates "AAA" from "BBB", and from "CCC", and tries to match them separately on each line. Only the lines that contain one (or more) of them get matched and printed.

54. Print lines that contain "AAA" and "BBB", and "CCC" in this order.

awk '/AAA.*BBB.*CCC/'

This one-liner uses a regular expression "AAA.*BBB.*CCC" to print lines. This regular expression says, "match lines containing AAA followed by any text, followed by BBB, followed by any text, followed by CCC in this order!" If a line matches, it gets printed.

55. Print only the lines that are 65 characters in length or longer.

awk 'length > 64'

This one-liner uses the "length" function. This function is defined as "length([str])" - it returns the length of the string "str". If none is given, it returns the length of the string in variable $0. For historical reasons, parenthesis () at the end of "length" can be omitted. This one-liner tests if the current line is longer than 64 chars, if it is, the "length > 64" evaluates to true and line gets printed.

56. Print only the lines that are less than 64 characters in length.

awk 'length < 64'

This one-liner is almost byte-by-byte equivalent to the previous one. Here it tests if the length if line less than 64 characters. If it is, Awk prints it out. Otherwise nothing gets printed.

57. Print a section of file from regular expression to end of file.

awk '/regex/,0'

This one-liner uses a pattern match in form 'pattern1, pattern2' that is called "range pattern". The 3rd Awk Tip from article "10 Awk Tips, Tricks and Pitfalls" explains this match very carefully. It matches all the lines starting with a line that matches "pattern1" and continuing until a line matches "pattern2" (inclusive). In this one-liner "pattern1" is a regular expression "/regex/" and "pattern2" is just 0 (false). So this one-liner prints all lines starting from a line that matches "/regex/" continuing to end-of-file (because 0 is always false, and "pattern2" never matches).

58. Print lines 8 to 12 (inclusive).

awk 'NR==8,NR==12'

This one-liner also uses a range pattern in format "pattern1, pattern2". The "pattern1" here is "NR==8" and "pattern2" is "NR==12". The first pattern means "the current line is 8th" and the second pattern means "the current line is 12th". This one-liner prints lines between these two patterns.

59. Print line number 52.

awk 'NR==52'

This one-liner tests to see if current line is number 52. If it is, "NR==52" evaluates to true and the line gets implicitly printed out (patterns without statements print the line unmodified).

The correct way, though, is to quit after line 52:

awk 'NR==52 { print; exit }'

This one-liner forces Awk to quit after line number 52 is printed. It is the correct way to print line 52 because there is nothing else to be done, so why loop over the whole doing nothing.

60. Print section of a file between two regular expressions (inclusive).

awk '/Iowa/,/Montana/'

I explained what a range pattern such as "pattern1,pattern2" does in general in one-liner #57. In this one-liner "pattern1" is "/Iowa/" and "pattern2" is "/Montana/". Both of these patterns are regular expressions. This one-liner prints all the lines starting with a line that matches "Iowa" and ending with a line that matches "Montana" (inclusive).

5. Selective Deletion of Certain Lines

There is just one one-liner in this section.

61. Delete all blank lines from a file.

awk NF

This one-liner uses the special NF variable that contains number of fields on the line. For empty lines, NF is 0, that evaluates to false, and false statements do not get the line printed.

Another way to do the same is:

awk '/./'

This one-liner uses a regular-expression match "." that matches any character. Empty lines do not have any characters, so it does not match.

Awk one-liners explained e-book

I have written my first e-book called "Awk One-Liners Explained". I improved the explanations of the one-liners in this article series, added new one-liners and added three new chapters - introduction to awk one-liners, summary of awk special variables and idiomatic awk. Please take a look:

Have Fun!

This concludes the article series about Awk one-liners. I hope that you enjoyed this three-part article and it made you a better Awk programmer!

My future plans are to create a awk1line-explained.txt that will be a supplementary file to the famous awk1line.txt. I am also thinking about publishing a nicely formatted pdf e-book about all the one-liners.

If you liked this article, you may also like a very similar article on Famous Sed One-Liners Explained.

And finally, if you notice anything that you can't understand, please let me know in the comments. Thank you!

Merry Christmas everyone!

If you're celebrating Christmas at your Unix console, wouldn't it be fun to have a Christmas tree in your shell? It sure would! Follow these steps to have your own Christmas tree in the shell.

Step 1: Install Acme::POE::Tree Perl Module.

Type the following at your shell, it will install Acme::POE::Tree Perl module:

perl -MCPAN -e 'install Acme::POE::Tree'

If you get notified that you are missing dependencies, answer 'yes' to have them installed.

Step 2: Celebrate Christmas at Console.

Type this to have your Christmas tree up and running:

perl -MAcme::POE::Tree -e 'Acme::POE::Tree->new()->run()'

The result:

Animated Acme::POE::Tree Perl Christmas Tree

Merry Christmas!

Ps. I created a geeky wish list at Amazon.com. I'd appreciate a Christmas or New Year present. The list is here: Peter's Amazon.com Wish List. Thank you! :)

This article is part of the article series "Sed One-Liners Explained."
<- previous article next article ->

sed -- the superman of unix stream editingThis is the second part of a three-part article on the famous sed one-liners. This part will explain sed one-liners for selective printing of certain lines. See part one for introduction of the series.

Just like the famous Awk one-liners, sed one-liners are beautiful, tiny little sed programs that span no more than 1 terminal line. They were written by Eric Pement and are floating around on the Internet as 'sed1line.txt' file.

If you are intrigued by this article series, I suggest that you subscribe to my posts!

Eric's sed one-liners are divided into several sections:

Update: Spanish translation of part two is available!

I have also made a sed cheat sheet that summarizes the whole sed utility. I suggest that you print it before you proceed and keep it in front of you. It will help you memorize the commands faster.

Awesome news: I have written an e-book based on this article series. Check it out:

Grab the sed1line.txt file and let's start.

4. Selective Printing of Certain Lines.

44. Print the first 10 lines of a file (emulates "head -10").

sed 10q

This one-liner restricts the "q" (quit) command to line "10". It means that this command gets executed only when sed reads the 10th line. For all the other lines there is no command specified. When there is no command specified, the default action is to print the line as-is. This one-liner prints lines 1-9 unmodified and at 10th line quits. Notice something strange? It was supposed to print first 10 lines of a file, but it seems that it just printed only the first 9... Worry not! The quit command is sneaky in its nature. Upon quitting with "q" command, sed actually prints the contents of pattern space and only then quits. As a result lines 1-10 get printed!

Please see the first part of the article for explanation of "pattern space".

45. Print the first line of a file (emulates "head -1").

sed q

The explanation of this one-liner is almost the same as of the previous. Sed quits and prints the first line.

A more detailed explanation - after the first line has been placed in the pattern space, sed executes the "q" command. This command forces sed to quit; but due to strange nature of the "q" command, sed also prints the contents of pattern space. As a result, only the first line gets printed.

46. Print the last 10 lines of a file (emulates "tail -10").

sed -e :a -e '$q;N;11,$D;ba'

This one-liner is tricky to explain. It always keeps the last 10 lines in pattern space and at the very last line of input it quits and prints them.

I'll try to explain it. The first "-e :a" creates a label called "a". The second "-e" does the following: "$q" - if it is the last line, quit and print the pattern space. If it is not the last line, execute three commands "N", "11,$D" and "ba". The "N" command reads the next line of input and appends it to the pattern space. The line gets separated from the rest of the pattern space by a new line character. The "11,$D" command executes the "D" command if the current line number is greater than or equal to 11 ("11,$" means from 11th line to end of file). The "D" command deletes the portion of pattern space up to the first new line character. The last command "ba" branches to a label named "a" (beginning of script). This guarantees that the pattern space never contains more than 10 lines, because as line 11 gets appended to pattern space, line 1 gets deleted, as line 12 gets appended line 2 gets deleted, etc.

47. Print the last 2 lines of a file (emulates "tail -2").

sed '$!N;$!D'

This one-liner is also tricky. First of all, the "$!" address restricts commands "N" and "D" to all the lines except the last line.

Notice how the addresses can be negated. If "$<command>" restricts a command to the last line, then "$!<command>" restricts the command to all but the last line. This can be applied to all restriction operations.

In this one-liner the "N" command reads the next line from input and appends it to pattern space. The "D" command deletes everything in pattern space up to the first "\n" symbol. These two commands always keep only the most recently read line in pattern space. When processing the second-to-last line, "N" gets executed and appends the last line to the pattern space. The "D" does not get executed as "N" consumed the last line. At this moment sed quits and prints out the last two lines of the file.

48. Print the last line of a file (emulates "tail -1").

sed '$!d'

This one-liner discards all the lines except the last one. The "d" command deletes the current pattern space, reads in the next line, and restarts the execution of commands from the first. In this case it just loops over itself like "dddd...ddd" until it hits the last line. At the last line no command is executed ("$!d" restricted execution of "d" to all the lines but last) and the pattern space gets printed.

Another way to do the same:

sed -n '$p'

The "-n" parameter suppresses automatic printing of pattern space. It means that without an explicit "p" command (or other commands that act directly on the output stream), sed is dead silent. The "p" command stands for "print" and it prints the pattern space. This one-liner calls the "p" command at the very last line of input. All the other lines are silently discarded.

49. Print next-to-the-last line of a file.

Eric gives three different one-liners to do this. The first one prints a blank line if the file contains just 1 line:

sed -e '$!{h;d;}' -e x

This one-liner executes the "h;d" commands for all the lines except the last one ("$!" restricts "h;d" commands to all lines except last). The "h" command puts the current line in hold buffer and "d" deletes the current line, and starts execution at the first sed command ("h;d" gets executed again, and again, ...). At every single line, that line gets copied to hold buffer. At the very last line "h;d" does not get executed. At this moment "x" gets a chance to execute. The "x" command exchanges the contents of hold buffer with pattern space. Remember that the previous line is still in the hold buffer. The "x" command puts it back in pattern space, and sed prints it! There you go, the next-to-last line was printed!

In case there is just 1 line in the file, only the "x" command gets executed. As the hold buffer initially is empty, "x" puts emptiness in pattern space (I use word "put" here but it actually exchanges the pattern space with hold space). Now sed prints the contents of pattern space, but it's empty, so sed prints out just a blank line.

The second prints the first line if the file contains just 1 line:

sed -e '1{$q;}' -e '$!{h;d;}' -e x

This sed-one liner is divided in two parts. The first part "1{$q;}" handles the case when the file contains just a single line. The second part "$!{h;d;} x" is exactly the same as in the previous one-liner! Thus, I need to explain just the first part.

The first part says - if it is the first line "1", then execute "$q". The "$q" command means - if it is the last line, then quit. What it effectively does is it quits if the first line is the last line (i.e. file contains just one line). Remember from one-liner #44 that before quitting sed prints the contents of pattern space. As a result, if the file contains just one line, sed prints it.

The third prints nothing for 1 line files:

sed -e '1{$d;}' -e '$!{h;d;}' -e x

This one-liner is again divided in two parts. The first part is "1{$d;}" and the second is exactly the same as in the previous two one-liners. I will explain just the first part.

The first part says - if it is the first line "1", then execute "$d". The "$d" command means - if it is the last line, then delete the pattern space and start all over again. In case the first line is the last (only one line in file), there is nothing more to be done and sed quits, printing nothing.

50. Print only the lines that match a regular expression (emulates "grep").

sed -n '/regexp/p'

This one-liner suppresses automatic printing of pattern space with the "-n" switch and makes use of "p" command to print only the lines that match "/regexp/". The lines that do not match this regex get silently discarded. The ones that match get printed. That's it.

Another one-liner that does the same:

sed '/regexp/!d'

This one-liner deletes all the lines that do not match "/regexp/". The other lines get printed by default. The "!" before "d" command inverts the line matching.

51. Print only the lines that do not match a regular expression (emulates "grep -v").

sed -n '/regexp/!p'

This one-liner is the inverse of the previous.

The "-n" prevents automatic printing of pattern space. The "/regexp/" restricts the "!p" command only to lines that match "/regexp/", but the "!" switch prevents "p" from acting on these lines. What happens is "p" acts on all lines that do not match "/regexp/", and they get "p"rinted.

sed '/regexp/d'

This one-liner is the inverse of the previous (#50).

This one-liner executed the "d" (delete) command on all lines that match "/regexp/", thus leaving only the lines that do not match. They get printed automatically.

52. Print the line immediately before regexp, but not the line containing the regexp.

sed -n '/regexp/{g;1!p;};h'

This one-liner saves each line in hold buffer with "h" command. If a line matches the regexp, the hold buffer (containing the previous line) gets copied to pattern space with "g" command and the pattern space gets printed out with "p" command. The "1!" restricts "p" not to print on the first line (as there are no lines before the first).

53. Print the line immediately after regexp, but not the line containing the regexp.

sed -n '/regexp/{n;p;}'

First of all, this one-liner disables automatic printing of pattern space with "-n" command line argument. Then, for all the lines that match "/regexp/", this one-liner executes "n" and "p" commands. The "n" command is the only command that depends on "-n" flag explicitly. If "-n" is specified it will empty the current pattern space and read in the next line of input. If "-n" is not specified, it will print out the current pattern space before emptying it. As in this one-liner "-n" is specified, the "n" command empties the pattern space, reads in the next line and then the "p" command prints that line out.

54. Print one line before and after regexp. Also print the line matching regexp and its line number. (emulates "grep -A1 -B1").

sed -n -e '/regexp/{=;x;1!p;g;$!N;p;D;}' -e h

First let's look at "h" command at the end of script. It gets executed on every line and stores the current line in pattern space in hold buffer. The idea of storing the current line in hold buffer is that if the next line matches "/regexp/" then the previous line is available in hold buffer.

Now let's look at the complicated "/regexp/{=;x;1!p;g;$!N;p;D;}" command. It gets executed only if the line matches "/regexp/". The first thing it does is it prints the current line number with "=" command. Then, it exchanges the hold buffer with pattern space by using the "x" command. As I explained, the "h" command at the end of the script makes sure that the hold buffer always contains the previous line. Now we have put it in the pattern space with "x" command. Next, if it's not the first line, "1!p" prints the pattern space, effectively printing the previous line. Now the "g" command gets executed. It copies the original line that was just exchanged with hold buffer back to pattern space. Now the "$!N" executes. If it is not the last line, "N" appends the next line to the current pattern space (and separates them with "\n" char). Pattern space now contains the line that matched "/regexp/" and the next line. The "p" command prints that. "D" deletes the current line (line that matched "/regexp/") from pattern space and finally "h" gets executed again, that puts the contents of pattern space into hold buffer. As "D" deleted the current line, the next line was put in hold buffer.

55. Grep for "AAA" and "BBB" and "CCC" in any order.

sed '/AAA/!d; /BBB/!d; /CCC/!d'

This one-liner inverts the "d" command to be executed on lines that do not contain either "AAA", "BBB" or "CCC". If a line does not contain one of them, it gets deleted and sed proceeds to the next line. Only if all three of the patterns are present, does the sed print the line.

56. Grep for "AAA" and "BBB" and "CCC" in that order.

sed '/AAA.*BBB.*CCC/!d'

This one-liner deletes lines that do not match regexp "/AAA.*BBB.*CCC/". For example, a line "AAAfooBBBbarCCC" will get printed but "AAAfooCCCbarBBB" baz will not.

It can also be written as:

sed -n '/AAA.*BBB.*CCC/p'

This one-liner prints lines that contain AAA...BBB...CCC in that order.

57. Grep for "AAA" or "BBB", or "CCC".

sed -e '/AAA/b' -e '/BBB/b' -e '/CCC/b' -e d

This one-liner uses the "b" command to branch to the end of the script if the line matches "AAA" or "BBB" or "CCC". At the end of the script the line gets implicitly printed. If the line does not match "AAA" or "BBB" or "CCC", the script reaches the "d" command that deletes the line.

gsed '/AAA\|BBB\|CCC/!d'

This one-liner works with GNU sed. GNU sed allows alternation operator | to be used to match separate things. It's a more compact way of saying match "AAA" or "BBB", or "CCC".

If you are using GNU sed, then there is actually no need to escape the pipes |. You may specify the "-r" command line option to use extended regular expressions. This way this one liner becomes:

gsed -r '/AAA|BBB|CCC/!d'

or

gsed -rn '/AAA|BBB|CCC/p'

58. Print a paragraph that contains "AAA". (Paragraphs are separated by blank lines).

sed -e '/./{H;$!d;}' -e 'x;/AAA/!d;'

First notice that this one-liner is divided in two parts for clearness. The first part is "/./{H;$!d;}" and the second part is "x;/AAA/!d".

The first part has an interesting pattern match "/./". What do you think it does? Well, a line separating paragraphs would be a blank line, meaning it would not have any characters in it. This pattern matches only the lines that are not separating paragraphs. These lines get appended to hold buffer with "H" command. They also get prevented from printing with "d" command (except for the last line, when "d" does not get executed ("$!" restricts "d" to all but the last line)). Once sed sees a blank line, the "/./" pattern no longer matches and the second part of one-liner gets executed.

The second part exchanges the hold buffer with pattern space by using the "x" command. The pattern space now contains the whole paragraph of text. Next sed tests if the paragraph contains "AAA". If it does, sed does nothing which results in printing the paragraph. If the paragraph does not contain "AAA", sed executes the "d" command that deletes it without printing and restarts execution at first command.

59. Print a paragraph if it contains "AAA" and "BBB" and "CCC" in any order.

sed -e '/./{H;$!d;}' -e 'x;/AAA/!d;/BBB/!d;/CCC/!d'

This one-liner is also split in two parts for clarity. The first part is exactly the same as the first part of previous one-liner. The second part is very similar to one-liner #55 and also the previous.

The "x" command in the 2nd part does exactly the same as in previous one-liner, it exchanges the hold buffer, that contains the paragraph with pattern space. Next sed does three tests - it tests if the paragraph contains "AAA", "BBB" and "CCC". If the paragraph does not contain even one of them, the "d" command gets executed that purges the paragraph. If it contains all three patterns, sed happily prints the paragraph.

60. Print a paragraph if it contains "AAA" or "BBB" or "CCC".

sed -e '/./{H;$!d;}' -e 'x;/AAA/b' -e '/BBB/b' -e '/CCC/b' -e d

The first part is exactly the same as in previous two one-liners and does not require explanation. The second part that happens to be "-e 'x;/AAA/b' -e '/BBB/b' -e '/CCC/b' -e d" is almost exactly the same as in one-liner #57.

The "x" command exchanges the paragraph stored in hold buffer with the pattern space. Then it tests if the pattern space (paragraph) contains "AAA", if it does, sed branches to end of script with "b" command, that happily makes sed print the paragraph. If "AAA" did not match, sed does exactly the same testing for pattern "BBB". If it again did not match, it tests for "CCC". If none of these patterns were found, sed executes the "d" command that deletes everything and restarts this one-liner.

Here is another way to do the same with GNU sed:

gsed '/./{H;$!d;};x;/AAA\|BBB\|CCC/b;d'

This one-liner is exactly the same as previous one. It just compresses the three tests for "AAA", "BBB" or "CCC" into one "/AAA\|BBB\|CCC/" as explained in one-liner #57.

61. Print only the lines that are 65 characters in length or more.

sed -n '/^.\{65\}/p'

This one-liner prints lines that are 65 characters in length or more. It does it by using a regular expression "^.{65}" that matches any 65 characters at the beginning of line. If there are less than 65 characters, the regex does not match and the line does not get printed (as automatic printing was disabled with "-n" command line option).

62. Print only the lines that are less than 65 chars.

sed -n '/^.\{65\}/!p'

This one-liner inverts the previous one. If the line matches 65 characters, then it is not printed "!p". If it does not match, it gets printed.

Another way to do the same:

sed '/^.\{65\}/d'

This one-liner deletes all lines that match 65 characters. All others implicitly get printed.

63. Print section of a file from a regex to end of file.

sed -n '/regexp/,$p'

This one-liner uses a tricky range match "/regex/,$". It matches lines starting from the first line that matches "/regex/" to the end of file "$". The "p" command prints these lines. All other lines get silently discarded.

64. Print lines 8-12 (inclusive) of a file.

sed -n '8,12p'

This is another type of range match. This range matches a section of lines between two lines numbers (inclusive). In this case it's lines [8 to 12].

sed '8,12!d'

This is the same one-liner, just written differently. It deletes lines that are outside of range [8, 12] and prints those in this range.

65. Print line number 52.

sed -n '52p'

This one-liner restricts the "p" command to line "52". Only this line gets "p"rinted.

sed '52!d'

This one-liner deletes all lines except line 52. Line 52 gets printed.

sed '52q;d'

This one is the smartest. It quits at line 52 with "q" command. The previous two one-liners would loop over all the remaining lines and do nothing. Remember from one-liner #44 that quit command prints the pattern space with it. The "d" command makes sure that no other line gets printed while sed gets to line 52.

66. Beginning at line 3, print every 7th line.

gsed -n '3~7p'

This one-liner uses a line range match extension of GNU sed. A line range in format "first~step" matches every step'th line starting from first. In this one-liner it's "3~7", meaning match every 7th line starting from 3rd. The "-n" flag prevents printing any other lines, and "p" in "3~7p" prints the matched line.

For everyone else, this one-liner works:

sed -n '3,${p;n;n;n;n;n;n;}'

This one-liner executes commands "p;n;n;n;n;n;n" for lines starting the 3rd line. The "3,$" is a line range match that restricts commands by line numbers. The "$" means end of file and "3" means 3rd line.

The "p;n;n;n;n;n;n" command prints the line, then skips 6, prints the 7th, skips 6, prints the 14th, etc. As it starts executing at line 3, the effect is - print line 3, skip 6, print line 10, skip 6, print line 17, .... That is, print every 7th line beginning at 3rd.

67. Print section of lines between two regular expressions (inclusive).

sed -n '/Iowa/,/Montana/p'

This one-liner prints all the lines between the first line that matches a regular expression "Iowa" and the first line that matches a regular expression "Montana".

It uses a range match "/start/,/finish/" that matches all lines starting from a line that matches "start" and ending with the first line that matches "finish".

An Important Comment About Ranges!

I have an important comment about ranges. Ranges in form "/start/,/finish/" always match 2 lines or more. If "/finish/" is on the same line as "/start/" it will not work. Please see the Sed FAQ 3.3 for more details.

Sed One-Liners Explained E-Book

I have written an e-book called "Sed One-Liners Explained". I improved the explanations of the one-liners in this article series, added new one-liners and added three new chapters - an introduction to sed, a summary of sed addresses and ranges, and debugging sed scripts with sed-sed. Please take a look:

Have Fun!

Have fun with sed, the superman of Unix text stream editing!

If you liked this article, you may also like a very similar article on Famous Awk One-Liners Explained.

Ps. If you notice anything that you can't understand, please let me know in the comments. Thanks!