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

Apologies if this is a newbie question, I havent been able to find a solution online. I have a loop that iterates through an array of filenames and I would like to break out of a nested loop to the next file in @filnames. I must be overlooking a simple solution or method that I am not aware of. I added the goto statement hoping to return to the outer loop, but I found this just restarts from the beginning of the foreach which is not what I wanted. edit: I noticed the label was on the line above the foreach loop. After moving inline with the loop, it is working properly. Thanks for the help, TIA

RECORD: foreach my $filenames (@filenames) { my $XML_infile = "C:/_OUTPUT/$filenames"; chomp $XML_infile; open INDATA, "C:/_OUTPUT/$filenames" or die "INDATA: $! \n\n "; while (!eof INDATA ) { my $line = <INDATA>; if ( $line =~ /\"PlateID\"/g ) { $outfile= ">C:/_OUTPUT/_DATA/$filenames" . $plate_id . ".t +xt"; if ( ($plate_id eq '' ) or ( ($FAM eq '' ) && ($VIC eq '' +) ) ) { popup_error_window($XML_infile) ; #Jump to next file in @filenames from here next RECORD; #Duh was staring right at me. } elsif () {#pull data for PlateID} } elsif () {#Process rest of file } } #complete processing data }#endforeach

Replies are listed 'Best First'.
Re: Busting out of an inner loop to next file in foreach loop
by choroba (Cardinal) on Mar 10, 2014 at 14:04 UTC
    If you want to start the next iteration of a loop that has the label NEXTRECORD, just use
    next NEXTRECORD;

    As you can see, naming the label just RECORD might make more sense.

    BTW, what is that goto supposed to do?

    لսႽ† ᥲᥒ⚪⟊Ⴙᘓᖇ Ꮅᘓᖇ⎱ Ⴙᥲ𝇋ƙᘓᖇ

      chorba, Thanks, was starting at me and I couldn't see it

        you changed the OP w/o indication. :(

        Cheers Rolf

        ( addicted to the Perl Programming Language)

Re: Busting out of an inner loop to next file in foreach loop
by LanX (Saint) on Mar 10, 2014 at 14:22 UTC
    I think you are looking for "last", in your code example you don't even need a label.

    HTH! :)

    Cheers Rolf

    ( addicted to the Perl Programming Language)

    update

    > I havent been able to find a solution online.

    duckduckgo or google "perl break loop"

Re: Busting out of an inner loop to next file in foreach loop
by kcott (Archbishop) on Mar 11, 2014 at 05:09 UTC

    G'day biohak,

    Welcome to the monastery.

    Firstly, please don't alter your OP without indicating what you've changed. See "How do I change/delete my post?" for an explanation of why not and how to indicate changes.

    The code you currently have posted has many issues:

    • "RECORD: foreach my $filenames (@filenames) {": The label is unnecessary (as ++LanX has pointed out) and each element of @filenames is one filename so let the variable reflect this, i.e. $filename.
    • "chomp $XML_infile;": This appears to be doing nothing: see chomp.
    • "open INDATA, "C:/_OUTPUT/$filenames" or die "INDATA: $! \n\n ";": Use the 3-argument form of open with a lexical filehandle; you already have the file path in $XML_infile so use it here; your die message should contain a filename (INDATA is a filehandle) — alternatively, use the autodie pragma.
    • "while  (!eof INDATA ) {": There's no need for eof here, just read from the filehandle (optionally assigning to a variable). See "perlsyn: Loop Control".
    • "my $line = <INDATA>;": See last point.
    • "if ( $line =~ /\"PlateID\"/g ) {": The 'g' modifier is for repeat matching which isn't what you're doing here. See "perlre: Modifiers".
    • "$outfile= ">C:/_OUTPUT/_DATA/$filenames" . $plate_id . ".txt";": You haven't assigned a value to $plate_id.
    • "next RECORD;": last is what you need here (as LanX has pointed out).
    • "elsif () {#pull data for PlateID}": It looks like that should be else {...}. See "perlsyn: Compound Statements".
    • "elsif () {#Process rest of file }": This looks unnecessary: I see no need for either elsif or else here.

    Using this dummy data (as I've no idea what your real data looks like):

    $ cat pm_1077685_A.txt Line 1: no plate info Line 2: ... PlateID 123 ... Line 3: ... PlateID 456 ... Line 4: no plate info $ cat pm_1077685_B.txt Line 1: no plate info Line 2: ... PlateID 789 ... Line 3: ... PlateID ... Line 4: no plate info $ cat pm_1077685_C.txt Line 1: no plate info Line 2: ... PlateID 000 ... Line 4: no plate info

    This script shows similar processing to what you appear to be attempting and includes examples of the points I've made above.

    #!/usr/bin/env perl use strict; use warnings; use autodie; my @filenames = qw{pm_1077685_A.txt pm_1077685_B.txt pm_1077685_C.txt} +; for my $filename (@filenames) { my $in_path = "./$filename"; print "Processing: '$in_path'\n"; open my $in_fh, '<', $in_path; while (<$in_fh>) { print "\t$_"; if (/PlateID/) { if (/PlateID (\d+)/) { my $plate_id = $1; print "\t\tProcess PlateID '$plate_id' from '$in_path' +\n"; } else { print "\t\tpopup_error_window($in_path)\n"; last; } } } }

    Output:

    $ pm_example.pl Processing: './pm_1077685_A.txt' Line 1: no plate info Line 2: ... PlateID 123 ... Process PlateID '123' from './pm_1077685_A.txt' Line 3: ... PlateID 456 ... Process PlateID '456' from './pm_1077685_A.txt' Line 4: no plate info Processing: './pm_1077685_B.txt' Line 1: no plate info Line 2: ... PlateID 789 ... Process PlateID '789' from './pm_1077685_B.txt' Line 3: ... PlateID ... popup_error_window(./pm_1077685_B.txt) Processing: './pm_1077685_C.txt' Line 1: no plate info Line 2: ... PlateID 000 ... Process PlateID '000' from './pm_1077685_C.txt' Line 4: no plate info

    -- Ken