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

Monks,

I'm having a problem using "until" while processing lines in a file. Specifically, I'm opening a file, and I want to skip all of the lines in it until I match a specific pattern; I then want to examine the rest of the file. Though I think this code should work, it doesn't (nothing is printed) ...
while (<LOG>) { do { next } until m/SCHEDULEREC OBJECT BEGIN SERVER_DAILY $da +te/; print ("$. : $_") if m/SCHEDULEREC OBJECT BEGIN SERVER_DAILY $da +te/; print ("$. : $_") if m/SCHEDULEREC OBJECT END SERVER_DAILY $date +/; print ("$. : $_") if m/ANS1228E Sending of object '(.*)' failed/ + };

I know that the pattern in my "do ... until" statement exists, because if I comment that line out, the next line prints the match. I'm sure I'm misunderstanding the way "next" and "until" works. Can someone give me a clue, please?

Thanks ... BlueFlashlight

Replies are listed 'Best First'.
Re: skipping lines in a file until regexp matches
by Aristotle (Chancellor) on Dec 17, 2002 at 20:16 UTC

    do { BLOCK } until $cond; executes the BLOCK at least once. Therefor, your next gets executed immediately and aborts the current iteration of the while loop. As a result, nothing ever gets printed.

    Further, the until indicates looping, but you don't iterate over anything in your BLOCK so it should be if.

    What you really want is a first loop that skips all the junk, and then a second one that does the work.

    do { $_ = <LOG> } until m/SCHEDULEREC OBJECT BEGIN SERVER_DAILY $date/ or not define +d; do { print ("$. : $_") if m/SCHEDULEREC OBJECT BEGIN SERVER_DAILY $date/ +; print ("$. : $_") if m/SCHEDULEREC OBJECT END SERVER_DAILY $date/; print ("$. : $_") if m/ANS1228E Sending of object '(.*)' failed/ $_ = <LOG>; } until not defined;

    Makeshifts last the longest.

Re: skipping lines in a file until regexp matches
by dpuu (Chaplain) on Dec 17, 2002 at 21:15 UTC
    You could also try the bistable operator (".." in scalar context):
    while (<LOG>) { next unless /START/..0; print; }
    will print all lines from the first that matches /START/. Use "/START/../END/" if you want to stop processing at the end of each section.

    --Dave

      Awesome! Thanks to everyone who responded; I went with dpuu's solution, as it seemed the easiest to "grok", and it worked perfectly!

      --blueflashlight
Re: skipping lines in a file until regexp matches
by jdporter (Paladin) on Dec 17, 2002 at 20:20 UTC
    The following is not necessarily the way I'd write it from scratch, but as a first revision from your code, I'd suggest this:
    while (<LOG>) { last if /SCHEDULEREC OBJECT BEGIN SERVER_DAILY $date/; } do { print "$. : $_" if /SCHEDULEREC OBJECT BEGIN SERVER_DAILY $dat +e/; print "$. : $_" if /SCHEDULEREC OBJECT END SERVER_DAILY $date/ +; print "$. : $_" if /ANS1228E Sending of object '(.*)' failed/; } while <LOG>;

    jdporter
    ...porque es dificil estar guapo y blanco.

Re: skipping lines in a file until regexp matches
by runrig (Abbot) on Dec 17, 2002 at 20:27 UTC
    Yet another way:
    my $start_pattern = qr/.... $date/; my $end_pattern = qr/.... $date/; my $send_pattern = qr/.... whatever/; while (<LOG>) { if (my $status = /$start_pattern/..1) { print "$. : $_" if $status == 1 or /$end_pattern/ or /$send_pattern/; } }
    Update: That should probably be (the first version only prints the start pattern once, this version will print it every time it occurs):
    while (<LOG>) { if (/$start_pattern/..1) { print "$. : $_" if /$start_pattern/ or /$end_pattern/ or /$send_pattern/; } }
    Another update: After dropping the status, I'd go with an answer with a 'next unless' like dpuu's answer below.