leoberbert has asked for the wisdom of the Perl Monks concerning the following question:

Dears,

I have the file below in the following format

Success|Filter passed|[invalid field]|[invalid field]|Id-350a875b08796 +5e58cbe1f4a Accept: text/plain, text/plain, application/json, application/*+json, +*/*, */* Host: api2.tim.com.br User-Agent: Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.3 +6 (KHTML, like Gecko) Chrome/52.0.2743.116 Safari/537.36 Via: 1.1 X-Forwarded-For: 144.22.98.123 X-Forwarded-Host: X-Forwarded-Server: Success|Success in calling policy shortcut|[invalid field]|[invalid fi +eld]|[invalid field]|Id-350a875b087965e58cbe1f4a|Call 'Set Request Me +ssage'|GET Accept: text/plain, text/plain, application/json, application/*+json, +*/*, */* Host: api2.tim.com.br User-Agent: Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.3 +6 (KHTML, like Gecko) Chrome/52.0.2743.116 Safari/537.36 Via: 1.1 api2.tim.com.br X-Forwarded-For: 144.22.98.123 X-Forwarded-Host: X-Forwarded-Server: Content-Type: text/xml; charset="UTF-8"

I need to perform a search for the line that begins with the string "^ Success" and display all the items until there is a "^ Sucess" string again.

Here is an example of what I need to display:

Success|Filter passed|[invalid field]|[invalid field]|Id-350a875b08796 +5e58cbe1f4a Accept: text/plain, text/plain, application/json, application/*+json, +*/*, */* Host: api2.tim.com.br User-Agent: Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.3 +6 (KHTML, like Gecko) Chrome/52.0.2743.116 Safari/537.36 Via: 1.1 X-Forwarded-For: 144.22.98.123 X-Forwarded-Host: X-Forwarded-Server:

What happens is that the amount of lines below after the match is very dynamic.

What happens is that the amount of lines below the match is very dynamic and in the same file there may be several lines of the same match and I would need to display them also when the file is run.

I do not know how to get the next line until the next occurrence. I can only catch the line of occurrence.

while ($line = <STDIN>) { chomp $line; if($line =~ /^Success.*Id-9952895b108957daeb296ba4/i) { print "$line\n"; } }
Could you guys help me?

Replies are listed 'Best First'.
Re: Search after match in dynamic lines
by choroba (Cardinal) on Aug 31, 2018 at 16:24 UTC
    Crossposted to StackOverflow. It's considered polite to inform about crossposting to prevent duplicate work of people not attending both the involved sites.

    Please, use the <CODE> tags for the input files.

    There's no line containing "^ Success" in your data. Do you mean qr/^ Success/?

    Have you tried the flip-flop operator?

    while (<>) { my $match = /^Success.*Id-/i ... /^Success/; print if $match && $match !~ /E/; }

    Three dots are similar to two dots, but the second match isn't attempted for the first matching line. The last matching line of a block returns its number with E0 appended, so it numerically remains the same, but you can test it's the last line.

    ($q=q:Sq=~/;[c](.)(.)/;chr(-||-|5+lengthSq)`"S|oS2"`map{chr |+ord }map{substrSq`S_+|`|}3E|-|`7**2-3:)=~y+S|`+$1,++print+eval$q,q,a,

      If the Ids are unique this is of course a good solution, but if not this has a caveat... if there happen to be two Success sections with the same Id right after each other, the second one won't be matched unless the second regex is changed accordingly:

      use warnings; use strict; my $ID = '5678'; while (<DATA>) { my $match = /^Success.*Id-\Q$ID\E/i ... /^Success.*Id-(?!\Q$ID\E)/i; print if $match && $match !~ /E/; } __DATA__ One Success|Id-abcd Two Success|Id-1234 Three Success|Id-abcd Four Success|Id-5678 Five Success|Id-5678 Six Success|Id-9900 Seven Success|Id-5678 Eight Success|Id-0000 Nine
Re: Search after match in dynamic lines
by haukex (Archbishop) on Aug 31, 2018 at 16:19 UTC

    One way is to keep a flag variable that keeps track of your state:

    use warnings; use strict; my $in_section=0; while (my $line = <>) { chomp $line; if ( $line =~ /^Success.*Id-9952895b108957daeb296ba4/i ) { print "$line\n"; $in_section = 1; } elsif ( $line =~/^Success/ ) { $in_section = 0; } elsif ($in_section) { print "$line\n"; } }

    Update now that you've formatted your post with <code> tags: Do these Success sections always have blank lines in between them, with no blank lines in the sections themselves?

Re: Search after match in dynamic lines
by AnomalousMonk (Archbishop) on Aug 31, 2018 at 16:20 UTC

    Untested:

    SUCCESS: while (my $line = <STDIN>) { next SUCCESS unless $line =~ /^Success.*Id-9952895b108957daeb296ba +4/i; print $line; /^Success/i && next SUCCESS or print while <STDIN>; }


    Give a man a fish:  <%-{-{-{-<

Re: Search after match in dynamic lines
by Marshall (Canon) on Aug 31, 2018 at 21:26 UTC
    Here are couple of ways to solve this:
    This first method is a way to do this without having to have a flag that indicates "inside the record".
    #!/usr/bin/perl use strict; use warnings; while (<DATA>) { process_record($_) if /^Success\|Filter passed/; } sub process_record { my $trigger_line = shift; print "$trigger_line"; print while (defined ($_ = <DATA>) and $_ =~ /\S/); print "\n"; } __DATA__ Success|Filter passed|[invalid field]|[invalid field]|Id-350a875b08796 +5e58cbe1f4a Accept: text/plain, text/plain, application/json, application/*+json, +*/*, */* Host: api2.tim.com.br User-Agent: Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.3 +6 (KHTML, like Gecko) Chrome/52.0.2743.116 Safari/537.36 Via: 1.1 X-Forwarded-For: 144.22.98.123 X-Forwarded-Host: X-Forwarded-Server: Success|Success in calling policy shortcut|[invalid field]|[invalid fi +eld]|[invalid field]|Id-350a875b087965e58cbe1f4a|Call 'Set Request Me +ssage'|GET Accept: text/plain, text/plain, application/json, application/*+json, +*/*, */* Host: api2.tim.com.br User-Agent: Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.3 +6 (KHTML, like Gecko) Chrome/52.0.2743.116 Safari/537.36 Via: 1.1 api2.tim.com.br X-Forwarded-For: 144.22.98.123 X-Forwarded-Host: X-Forwarded-Server: Content-Type: text/xml; charset="UTF-8" Success|Filter passed|[invalid field]|[invalid field]|Id-350a875b08796 +5e58cbe1f4a Accept: text/plain, text/plain, application/json, application/*+json, +*/*, */* Host: api2.tim.com.br User-Agent: Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.3 +6 (KHTML, like Gecko) Chrome/52.0.2743.116 Safari/537.36 Via: 1.1 X-Forwarded-For: 144.22.98.123 X-Forwarded-Host: X-Forwarded-Server:
    Another way...
    Perl has a special operator that will keep track of the "inside the record" flag for you..
    #see https://www.perlmonks.org/?node_id=525392 while (<DATA>) { print if (/^Success\|Filter passed/ ... /^\s*$/); }