I'm running the following command against a log file and only wanting to get the last/latest match. Sometimes there may only be one match, other times there may be multiple, which is causing an issue for me since the following command is returning both matches:

cat "$(ls -t | head -n1)" | grep -P "(NODE1[\s\S]*TEST\s=\sPOWER[\s\S]*OUTPUT\s=\s\d+?.*\s+;?)"

>>>>> (results in)...

NODE1 2018-03-06 12:01:23
  EVENT_TIME = 2018-03-06 12:01:23
  OUTPUT = 12


NODE1 2018-03-06 12:03:23
  EVENT_TIME = 2018-03-06 12:03:23
  OUTPUT = 7


I need the last matching group in the event there are multiple. Is this possible with grep/regex or do I need to pipe the results into sed/awk? If so, how?

  • Hard way is pipe your commant to tail -n <number_of_lines_of_your_group>. Mar 6, 2018 at 21:17
  • @YurijGoncharuk problem is I don't know how many lines I need to capture.
    – Godzilla74
    Mar 6, 2018 at 21:18
  • You can use 'tac' instead of 'cat' and rewrite grep pattern for backward. Mar 6, 2018 at 21:22
  • If it's possible, put little sample of file in patebin.com. I will try to write pattern. Mar 6, 2018 at 21:24
  • @YurijGoncharuk pastebin.com/n2iDY8uY
    – Godzilla74
    Mar 6, 2018 at 21:36

3 Answers 3


I propose to you this solution:

cat <your_source_file> | sed -n '/NODE1/,/;/p' | tr '\n' '|' | awk -F ';' '{print $(NF-1)}'|tr '|' '\n'

sed -n '/NODE1/,/;/p' - find 'NODE1' blocks.

tr '\n' '|' convert newlines to record separator, so table columns will be separated by ';'.

awk -F ';' '{print $(NF-1)}' - print last-1 table column.

tr '|' '\n' - backward to previous view for record.

awk -F ';' '{for(i=(NF-1); i>0; i--){ if($i ~ "TEST = POWER"){print $i} } }' - only "TEST = POWER" events.

  • You're the man! This is way more consistent than the results I was getting to tac | .. | tac
    – Godzilla74
    Mar 6, 2018 at 22:33
  • One question... how can I amend this to only get the last 'TEST = POWER` command run?
    – Godzilla74
    Mar 6, 2018 at 22:35
  • Just a minute, I'm trying :) I have an idea. Mar 6, 2018 at 22:45
  • I've supplemented answer with your wishes ;) Mar 6, 2018 at 23:07

Based on Yurij's suggestion, I started looking into using tac instead of cat, and reversing my grep statement. Now, I'm looking at the file from the bottom up and grabbing the first match:

tac "$(ls -t | head -n1)" | grep -m 1 -P "\d+[\s\S]*TEST\s=\sTXPOWER" | tac


I find perl more convenient for this:

perl -lane 'if(/^NODE1 /&&($#n=-1)../^;$/){push @n,$_} END{print $_ for @n}' file


perl Practical Extraction and Reporting Language.
-lane switches commonly helpful for one-liners.
' start of the actual program instructions
if(/^NODE1 /&&($#n=-1)../^;$/) consider only portions of text beginning with a line stat starts with NODE1 followed by a whitespace, and ending with a line containing a single semicolon.
/^NODE1 /&&($#n=-1) reset the @n array at the start of the text portion.
{push @n,$_} save each line in the text portion as an element of an array called @n
END{print $_ for @n} when the whole file has been parsed, print the text portion saved in @n.
' end of the program instructions.
file this is a placeholder for the name of the file you wish to process.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.