Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Grep a Log file for the last occurrence of a string between two strings

Tags:

I have a log file trace.log. In it I need to grep for the content contained within the strings <tag> and </tag>. There are multiple sets of this pair of strings, and I just need to return the content between last set (in other words, from the tail of the log file).

Extra Credit: Any way I can return the content contained within the two strings only if the content contains "testString"?

Thanks for looking.

EDIT: The search parameters and are contained on different lines with about 100 lines of content separating them. The content is what I'm after...

like image 477
rs79 Avatar asked Oct 30 '13 11:10

rs79


People also ask

How do you find the last occurrence of a string in Unix?

The command is relatively simple. We start by finding the string we require using grep. Next, Grep will list all the string occurrences, and finally, we pipe the output to the tail and locate the last line of the output.

How do you find the last occurrence of a character in a string in Linux?

The strrchr() function finds the last occurrence of c (converted to a character) in string .

How do I use grep in logs?

grep is a command line tool that can search for matching text in a file, or in output from other commands. It's included by default in most Linux distributions and is also available for Windows and Mac. To perform a simple search, enter your search string followed by the file you want to search.


2 Answers

Use tac to print the file the other way round and then grep -m1 to just print one result. The look behind and look ahead checks text in between <tag> and </tag>.

tac a | grep -m1 -oP '(?<=tag>).*(?=</tag>)' 

Test

Given this file

$ cat a <tag> and </tag> aaa <tag> and <b> other things </tag> adsaad <tag>and  last one</tag>  $ tac a | grep -m1 -oP '(?<=tag>).*(?=</tag>)' and  last one 

Update

EDIT: The search parameters and are contained on different lines with about 100 lines of content separating them. The content is what I'm after...

Then it is a bit more tricky:

tac file | awk '/<\/tag>/ {p=1; split($0, a, "</tag>"); $0=a[1]};                 /<tag>/   {p=0; split($0, a, "<tag>");  $0=a[2]; print; exit};                 p' | tac 

The idea is to reverse the file and use a flag p to check if the <tag> has appeared yet or not. It will start printing when </tag> appears and finished when <tag> comes (because we are reading the other way round).

  • split($0, a, "</tag>"); $0=a[1]; gets the data before </tag>
  • split($0, a, "<tag>" ); $0=a[2]; gets the data after <tag>

Test

Given a file a like this:

<tag> and </tag> aaa <tag> and <b> other thing come here and here </tag>  some text<tag>tag is starting here blabla and ends here</tag> 

The output will be:

$ tac a | awk '/<\/tag>/ {p=1; split($0, a, "</tag>"); $0=a[1]}; /<tag>/ {p=0; split($0, a, "<tag>"); $0=a[2]; print; exit}; p' | tac tag is starting here blabla and ends here 
like image 198
fedorqui 'SO stop harming' Avatar answered Oct 26 '22 08:10

fedorqui 'SO stop harming'


If like me, you don't have access to tac because your sysadmin won't play ball you can try:

grep pattern file | tail -1 
like image 41
SlackGadget Avatar answered Oct 26 '22 10:10

SlackGadget