Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Printing with sed or awk a line following a matching pattern

Tags:

sed

awk

Question: I'd like to print a single line directly following a line that contains a matching pattern.

My version of sed will not take the following syntax (it bombs out on +1p) which would seem like a simple solution:

sed -n '/ABC/,+1p' infile 

I assume awk would be better to do multiline processing, but I am not sure how to do it.

like image 829
user1537723 Avatar asked Jul 28 '13 13:07

user1537723


People also ask

How do I print to the next line in awk?

Original answer: Append printf "\n" at the end of each awk action {} . printf "\n" will print a newline.

What is pattern matching in awk?

Any awk expression is valid as an awk pattern. The pattern matches if the expression's value is nonzero (if a number) or non-null (if a string). The expression is reevaluated each time the rule is tested against a new input record.

What is awk '{ print $1 }'?

If you notice awk 'print $1' prints first word of each line. If you use $3, it will print 3rd word of each line.

Can we search a pattern using awk?

In awk, regular expressions (regex) allow for dynamic and complex pattern definitions. You're not limited to searching for simple strings but also patterns within patterns. You have selected all records containing the letter p followed by either an e or an l.


2 Answers

Never use the word "pattern" as is it highly ambiguous. Always use "string" or "regexp" (or in shell "globbing pattern"), whichever it is you really mean.

The specific answer you want is:

awk 'f{print;f=0} /regexp/{f=1}' file 

or specializing the more general solution of the Nth record after a regexp (idiom "c" below):

awk 'c&&!--c; /regexp/{c=1}' file 

The following idioms describe how to select a range of records given a specific regexp to match:

a) Print all records from some regexp:

awk '/regexp/{f=1}f' file 

b) Print all records after some regexp:

awk 'f;/regexp/{f=1}' file 

c) Print the Nth record after some regexp:

awk 'c&&!--c;/regexp/{c=N}' file 

d) Print every record except the Nth record after some regexp:

awk 'c&&!--c{next}/regexp/{c=N}1' file 

e) Print the N records after some regexp:

awk 'c&&c--;/regexp/{c=N}' file 

f) Print every record except the N records after some regexp:

awk 'c&&c--{next}/regexp/{c=N}1' file 

g) Print the N records from some regexp:

awk '/regexp/{c=N}c&&c--' file 

I changed the variable name from "f" for "found" to "c" for "count" where appropriate as that's more expressive of what the variable actually IS.

f is short for found. Its a boolean flag that I'm setting to 1 (true) when I find a string matching the regular expression regexp in the input (/regexp/{f=1}). The other place you see f on it's own in each script it's being tested as a condition and when true causes awk to execute its default action of printing the current record. So input records only get output after we see regexp and set f to 1/true.

c && c-- { foo } means "if c is non-zero then decrement it and if it's still non-zero then execute foo" so if c starts at 3 then it'll be decremented to 2 and then foo executed, and on the next input line c is now 2 so it'll be decremented to 1 and then foo executed again, and on the next input line c is now 1 so it'll be decremented to 0 but this time foo will not be executed because 0 is a false condition. We do c && c-- instead of just testing for c-- > 0 so we can't run into a case with a huge input file where c hits zero and continues getting decremented so often it wraps around and becomes positive again.

like image 128
Ed Morton Avatar answered Sep 21 '22 09:09

Ed Morton


It's the line after that match that you're interesting in, right? In sed, that could be accomplished like so:

sed -n '/ABC/{n;p}' infile 

Alternatively, grep's A option might be what you're looking for.

-A NUM, Print NUM lines of trailing context after matching lines. 

For example, given the following input file:

foo bar baz bash bongo 

You could use the following:

$ grep -A 1 "bar" file bar baz $ sed -n '/bar/{n;p}' file baz 

Hope that helps.

like image 32
chooban Avatar answered Sep 20 '22 09:09

chooban