LinuxQuestions.org

LinuxQuestions.org (/questions/)
-   Linux - Newbie (http://www.linuxquestions.org/questions/linux-newbie-8/)
-   -   AWK print line only if next line matches a string (http://www.linuxquestions.org/questions/linux-newbie-8/awk-print-line-only-if-next-line-matches-a-string-906096/)

wolverene13 10-02-2011 03:24 PM

AWK print line only if next line matches a string
 
Hi,

I am relatively new to awk and I was searching all over the place for the answer to this, but can't really find anything valid. I was wondering how to only print a line if the next line matches a string.

I started with something like this:

NODE_1
port 1
description blah
port 2
description blah blah
NODE_2
port 1
description blah
port 2
description blah
NODE_3
port 1
port 2
NODE_4
port 1
port 2
NODE_5
port 1
port 2
NODE_6
port 1
description blahdy blah
port 2
description floop-a-doop

Originally my intention was to exclude any ports that don't have descriptions, while leaving the node names intact.

I've tried:
Code:

awk '/^NODE/;{print};/^description/;{print x; print};{x=$0}'
...to print all "NODE" lines and any "description" line as well as the previous "port" line above it (kudos to crts for that answer).

Now I get this:

NODE_1
port 1
description blah
port 2
description blah blah
NODE_2
port 1
description blah
port 2
description blah
NODE_3
NODE_4
NODE_5
NODE_6
port 1
description blahdy blah
port 2
description floop-a-doop

Which I thought was what was needed, but apparently we don't need the node names of devices that have ports without descriptions at all. So I essentially need to get rid of the node names that are not followed by the string "port". Desired output should look like this:

NODE_1
port 1
description blah
port 2
description blah blah
NODE_2
port 1
description blah
port 2
description blah
NODE_6
port 1
description blahdy blah
port 2
description floop-a-doop

Any help would be greatly appreciated, and if it would help, I can post the actual content rather than all the "blahs" everything if that helps.

Thanks in advance!

Tinkster 10-02-2011 03:40 PM

Code:

awk '/^port/{port=$0}/^description/{print port;print $0}' nodes
port 1
description blah
port 2
description blah blah
port 1
description blah
port 2
description blah
port 1
description blahdy blah
port 2
description floop-a-doop

Works as desired w/ the current data sample.

wolverene13 10-02-2011 03:51 PM

Quote:

Originally Posted by Tinkster (Post 4488329)
Code:

awk '/^port/{port=$0}/^description/{print port;print $0}' nodes
port 1
description blah
port 2
description blah blah
port 1
description blah
port 2
description blah
port 1
description blahdy blah
port 2
description floop-a-doop

Works as desired w/ the current data sample.

That looks like it would work, but it doesn't appear to print the node names - while I need the ports and their descriptions, I do also need the node name listed before each set of ports and their respective descriptions.

Tinkster 10-02-2011 04:02 PM

Quote:

Originally Posted by wolverene13 (Post 4488341)
That looks like it would work, but it doesn't appear to print the node names - while I need the ports and their descriptions, I do also need the node name listed before each set of ports and their respective descriptions.

Oops - easy fix.
Code:

awk '/^NODE/{print $0}/^port/{port=$0}/^description/{print port;print $0}' nodes
NODE_1
port 1
description blah
port 2
description blah blah
NODE_2
port 1
description blah
port 2
description blah
NODE_3
NODE_4
NODE_5
NODE_6
port 1
description blahdy blah
port 2
description floop-a-doop


wolverene13 10-02-2011 04:08 PM

Quote:

Originally Posted by Tinkster (Post 4488347)
Oops - easy fix.
Code:

awk '/^NODE/{print $0}/^port/{port=$0}/^description/{print port;print $0}' nodes
NODE_1
port 1
description blah
port 2
description blah blah
NODE_2
port 1
description blah
port 2
description blah
NODE_3
NODE_4
NODE_5
NODE_6
port 1
description blahdy blah
port 2
description floop-a-doop


Well, that's kind of back to square 1; Essentially I need a way to make NODE_3, NODE_4, and NODE_5 go away because they don't have any ports with descriptions on them.

EDIT: Essentially I need something that says: "If the next line after NODE does not begin with "port", don't print NODE either."

Tinkster 10-03-2011 01:18 PM

Quote:

Originally Posted by wolverene13 (Post 4488352)
Well, that's kind of back to square 1; Essentially I need a way to make NODE_3, NODE_4, and NODE_5 go away because they don't have any ports with descriptions on them.

EDIT: Essentially I need something that says: "If the next line after NODE does not begin with "port", don't print NODE either."

That description is actually wrong. What you want is: "If the line after port isn't description
don't print node and port either."
Code:

awk '/^NODE/{node=$0}/^port/{port=$0}/^description/{if(prev!=node){print node};print port;print $0;prev=node}' nodesNODE_1
port 1
description blah
port 2
description blah blah
NODE_2
port 1
description blah
port 2
description blah
NODE_6
port 1
description blahdy blah
port 2
description floop-a-doop


Cheers,
Tink

wolverene13 10-03-2011 01:55 PM

Quote:

Originally Posted by Tinkster (Post 4488984)
That description is actually wrong. What you want is: "If the line after port isn't description
don't print node and port either."
Code:

awk '/^NODE/{node=$0}/^port/{port=$0}/^description/{if(prev!=node){print node};print port;print $0;prev=node}' nodes
NODE_1
port 1
description blah
port 2
description blah blah
NODE_2
port 1
description blah
port 2
description blah
NODE_6
port 1
description blahdy blah
port 2
description floop-a-doop


Cheers,
Tink

Perfect! That's exactly what I needed! Thanks a lot!!

I'd hate to bother you, but if I'm understanding the syntax right:

awk '/^NODE/{node=$0} is essentially "search for lines beginning with "NODE" and "remember" those lines in $0 and collectively call them "node""

/^port/{port=$0} is pretty much the same thing, except searching for lines containing "port", which then join all the "NODE" lines in $0, and collectively called "port"

This is where it gets fuzzy for me:
/^description/{if(prev!=node){print node};print port;print $0;prev=node}'

Does that mean "search for lines beginning with "description", create a variable that is called "prev", then if prev does not equal anything in "node", print everything in "node", print everything in "port", and everything "remembered" in $0" then prev=node? Sorry if that's way off, but I'm fairly new to awk and like to actually learn what I'm doing, rather then just regurgitate the answers that I receive. Thanks for the help!

Tinkster 10-03-2011 02:15 PM

Quote:

Originally Posted by wolverene13 (Post 4489018)
Perfect! That's exactly what I needed! Thanks a lot!!

I'd hate to bother you, but if I'm understanding the syntax right:

awk '/^NODE/{node=$0} is essentially "search for lines beginning with "NODE" and "remember" those lines in $0 and collectively call them "node""

/^port/{port=$0} is pretty much the same thing, except searching for lines containing "port", which then join all the "NODE" lines in $0, and collectively called "port"

Not quite ... there's no "collective" there. port and node are variables
that will get populated every time a line begins w/ NODE or port, respectively.
The whole string of expressions gets applied to each line of your nodes file.



Quote:

Originally Posted by wolverene13 (Post 4489018)
This is where it gets fuzzy for me:
/^description/{if(prev!=node){print node};print port;print $0;prev=node}'

Does that mean "search for lines beginning with "description", create a variable that is called "prev", then if prev does not equal anything in "node", print everything in "node", print everything in "port", and everything "remembered" in $0" then prev=node? Sorry if that's way off, but I'm fairly new to awk and like to actually learn what I'm doing, rather then just regurgitate the answers that I receive. Thanks for the help!

The prev variable and its comparison against node are there so we don't
print NODE for each port line w/ a description, in other words to avoid
the following output:
Code:

NODE_1
port 1
description blah
NODE_1
port 2
description blah blah
NODE_2
port 1
description blah
NODE_2
port 2
description blah
NODE_6
port 1
description blahdy blah
NODE_6
port 2
description floop-a-doop



HIH.


Cheers,
Tink

wolverene13 10-03-2011 03:32 PM

Quote:

Originally Posted by Tinkster (Post 4489026)
Not quite ... there's no "collective" there. port and node are variables
that will get populated every time a line begins w/ NODE or port, respectively.
The whole string of expressions gets applied to each line of your nodes file.





The prev variable and its comparison against node are there so we don't
print NODE for each port line w/ a description, in other words to avoid
the following output:
Code:

NODE_1
port 1
description blah
NODE_1
port 2
description blah blah
NODE_2
port 1
description blah
NODE_2
port 2
description blah
NODE_6
port 1
description blahdy blah
NODE_6
port 2
description floop-a-doop



HIH.


Cheers,
Tink

Perfect! Thanks again!!


All times are GMT -5. The time now is 09:41 PM.