Wayne A.
Wayne A.

Reputation: 39

perl multiline issue: need one liner to print last match before string in file

I have a log file like this:

2018-07-10 10:03:01: random text1
2018-07-10 10:03:02: random text2
2018-07-10 10:03:03: random text3
    more text
    and more
    THIS IS MATCHED STRING
2018-07-10 10:03:04: random text4

I want to use a perl one-liner to find the most recent timestamp before "THIS IS MATCHED STRING".

I tried this:

perl -0777 -nle 'print "$1\n" while m/(\d\d\d\d-\d\d-\d\d \d\d:\d\d:\d\d).+?THIS IS MATCHED STRING/sg'

But it matched the first timestamp, "2018-07-10 10:03:01" instead of the "2018-07-10 10:03:03" that I wanted. Obviously (at least I think), I don't have a good understanding of how the greedy/lazy matching is working.

Any help would be appreciated!

Upvotes: 1

Views: 187

Answers (2)

zdim
zdim

Reputation: 66883

For a fairly elementary approach, which avoids an involved regex, process line by line and when a timestamp pattern is matched record it. Then as you run into pattern THIS... you will have had the (last) previous timestamp.

perl -wnE'
    $ts = $1 if /(\d{4}-\d{2}-\d{2}[ ]\d{2}:\d{2}:\d{2})/; 
    say $ts // "no previous time stamp"  if /THIS IS MATCHED STRING/;
' file.txt

If the timestamp is captured and saved with ($ts) = /.../ then failed matches on lines without it turn it undef, so it may not be there when THIS is found. Thus it is saved from $1 only once there is a match.

The defined-or (//) on $ts is used in case the file had no time stamps at all before THIS

Upvotes: 3

Jan
Jan

Reputation: 43169

You could use

^
(\d{4}-\d{2}-\d{2}\ \d+:\d+:\d+):
(?:(?!^\d{4})[\s\S])+?
\QTHIS IS MATCHED STRING\E

See a demo on regex101.com.

Upvotes: 0

Related Questions