LinuxQuestions.org

LinuxQuestions.org (/questions/)
-   Programming (http://www.linuxquestions.org/questions/programming-9/)
-   -   Sed command to print matching lines and 2 lines above.. (http://www.linuxquestions.org/questions/programming-9/sed-command-to-print-matching-lines-and-2-lines-above-673139/)

DX398 09-29-2008 02:54 PM

Sed command to print matching lines and 2 lines above..
 
Hello everyone,

I'm looking to print matching lines including the 3 lines above the matched line. I have come up with the following command but it's only printing 1 line above. In the example below the output is missing the Host Name and the following blank line. Anyone known what I'm missing here?


sed -n /192.168.12/{x;p;x;p};h <input.txt >output.txt

input.txt

Host Name: SERVER1

NetBIOS over TCP/IP: Enabled
IP Address: 192.168.12.111

-----------------------------
output.txt


NetBIOS over TCP/IP: Enabled
IP Address: 192.168.12.111

CRC123 09-29-2008 03:06 PM

If you're not trying to replace any of the text, then the grep command has an option to do this:
Code:

grep -B 3 "192.168.12.11" <file.txt> > outfile.txt
You may play around with it to get what you want, but the man pages of grep have a section called 'Context Line Control' that discusses what you are trying to do.

DX398 09-30-2008 08:25 AM

Thanks crc123, but is there anyway SED can do this?

pixellany 09-30-2008 08:38 AM

Quote:

Originally Posted by DX398 (Post 3295923)
Thanks crc123, but is there anyway SED can do this?

The rational answer is: Why?
This said, I will confess that I often do such things---if only to see if it can be done.

The problem with SED is that it operates one line at a time. To do what you want, you have to append lines to the hold register and then pull out the combination to test it. If the test failed, you would then have to delete one of the lines and add a new one.

I visualize some messy-looking code....

Really good SED tutorial here:
http://www.grymoire.com/Unix/Sed.html

pixellany 09-30-2008 08:55 AM

Look what I found:
http://www.grymoire.com/Unix/Sed.html#uh-54
He calls it "context grep"

keefaz 09-30-2008 09:01 AM

Maybe this could work:
Code:

sed -n '/Host Name/,/192.168.12.111/p' input.txt > output.txt

pixellany 09-30-2008 09:04 AM

I think OP wanted the 3 previous lines without knowing the content...ie the only thing known was the desired pattern in the last line.

ghostdog74 09-30-2008 09:32 AM

Quote:

Originally Posted by DX398 (Post 3295923)
Thanks crc123, but is there anyway SED can do this?

sed is not the correct tool for such task. there's actually an algorithm for this. It uses variables to store every 3 lines.
Code:

awk '
/pattern/{
 print first
 print second
 print third
}
{
 third=second
 second=first
 first=$0
}
' file

output:
Code:

# more file
this is line 1
this is line 2
this is line 3
this is line 4
search pattern
this is line 5
this is line 6

# ./testnew.sh
this is line 4
this is line 3
this is line 2

the order is jumbled, but you get the picture.

radoulov 09-30-2008 10:22 AM

If the file is not too large:

Code:

perl -0ne'print /((?:.*\n){3}.*search pattern.*\n)/g' filename

DX398 09-30-2008 11:08 AM

Quote:

Originally Posted by pixellany (Post 3295958)
I think OP wanted the 3 previous lines without knowing the content...ie the only thing known was the desired pattern in the last line.


That's correct, I don't know the value of the previous lines.

pixellany 09-30-2008 11:25 AM

I finally figured out the original syntax:

Code:

sed -n /192.168.12/{x;p;x;p};h <input.txt >output.txt
What this does is to write (copy) each line to the hold buffer until the pattern is found. Then it exchanges the pattern buffer and hold buffer, prints, and then repeats. Thus you get the last thing copied to the hold buffer, and then the line where the pattern matched.

What you need is "H" (append), instead of "h" (copy)

This is crude, but works:

Code:

sed -n '/keyword/{H;g;p};H' filename|tail -n3 > newfilename
In the reference I gave you, read carefully about h, H, g, G, and x

Kenhelm 09-30-2008 12:19 PM

The following is adapted from a sed emulation of the tail command at
http://www.gnu.org/software/sed/manual/sed.html#tail
It creates a moving window of four lines.
The '$' end of line marker is essential as the pattern space will usually contain four file lines and '192.168.12.111' could be in any of them, but we only want to print when its in the last one, i.e. at the end of the pattern space.
Code:

sed -n '1h;2,4 {; H; g; };/192.168.12.111$/p;1,3d;N;D' input.txt
This is a more pragmatic method which uses tac (to reverse the order of the lines) and GNU sed:-
Code:

tac input.txt | sed -n '/192.168.12/,+3p' | tac
EDIT:
These solutions give the matched line and the three lines above.
If only two lines above are required change 4 to 3, and 3 to 2 in the code.
(Both versions of the problem appear in the thread)

DX398 10-01-2008 08:25 AM

Thank You! I get it now...you guys are amazing!


All times are GMT -5. The time now is 03:38 PM.