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

Hi PerlMonks I am a newbie in perl .. I am using nested while loops to open two files for searching data as below

open(file_one,"ABC"); while(my $line = <file_one>) { open(file_two,"CDE"); while(my $line2=<file_two>) { print "line : $line line2 : $line2 \n"; } close(file_two); }

The problem is nothing is printed against line : <blank> line2: <somevalue>

Replies are listed 'Best First'.
Re: Nested While loop not working
by choroba (Cardinal) on Mar 11, 2014 at 08:58 UTC
    Do you check Perl was able to open the files? Use or die
    open my $file_one, '<', 'ABC' or die $!;

    or, use autodie.

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

      Hi I have tried it (the thing is when i remove second loop its printing the $line value )

        No, Your code is working for me without removing the second loop.

        use strict; use warnings; open(file_one,"<","ABC")or die $!; while(my $line = <file_one>) { open(file_two,"<","CDE") or die $!; while(my $line2=<file_two>) { print "line : $line line2 : $line2 \n"; } close(file_two); }

        line : test
        line2 : CDE

        line : test
        line2 : CDEEE

        line : test
        line2 : CDEEEE

        line : test121212121
        line2 : CDE

        line : test121212121
        line2 : CDEEE

        line : test121212121
        line2 : CDEEEE

        line : adskjdsadjdka
        line2 : CDE

        line : adskjdsadjdka
        line2 : CDEEE

        line : adskjdsadjdka
        line2 : CDEEEE

        Update:

        Added file content.

        ABC:

        test
        test121212121
        adskjdsadjdka

        CDE:

        CDE
        CDEEE
        CDEEEE


        All is well
Re: Nested While loop not working
by kcott (Archbishop) on Mar 11, 2014 at 10:10 UTC

    G'day Manisha,

    Welcome to the monastery.

    I created two files:

    $ cat ABC qwe asd zxc $ cat CDE rty fgh vbn

    I ran your code like this (apart from the shebang and three use lines, it's a copy of what you posted):

    #!/usr/bin/env perl use strict; use warnings; use autodie; open(file_one,"ABC"); while(my $line = <file_one>) { open(file_two,"CDE"); while(my $line2=<file_two>) { print "line : $line line2 : $line2 \n"; } close(file_two); }

    I got a warning but then output from both files, like this:

    Name "main::file_one" used only once: possible typo at ./pm_example.pl + line 8. line : qwe line2 : rty line : qwe line2 : fgh line : qwe line2 : vbn line : asd line2 : rty line : asd line2 : fgh line : asd line2 : vbn line : zxc line2 : rty line : zxc line2 : fgh line : zxc line2 : vbn

    So, check the filenames, file permissions and file contents. If you ask for diagnostic messages, you'll usually get useful information: see Pragmas for documentation on those that I used; while you're learning, diagnostics can also be useful but don't leave it in production code.

    Here's a better way to write it:

    #!/usr/bin/env perl use strict; use warnings; use autodie; open my $fh1, '<', 'ABC'; while (defined(my $line1 = <$fh1>)) { chomp $line1; open my $fh2, '<', 'CDE'; while (defined(my $line2 = <$fh2>)) { chomp $line2; print "line1 : $line1 line2 : $line2\n"; } }

    Now the output has no warnings and all those extra newlines are gone:

    line1 : qwe line2 : rty line1 : qwe line2 : fgh line1 : qwe line2 : vbn line1 : asd line2 : rty line1 : asd line2 : fgh line1 : asd line2 : vbn line1 : zxc line2 : rty line1 : zxc line2 : fgh line1 : zxc line2 : vbn

    See the following for information on what I did differently to your posted code: chomp; defined; and open. Also, the following have useful information regarding while loops: "perlsyn: Loop Control" and "perlop: I/O Operators". Finally, if you've only just started to learn Perl, I recommend you first read all of "perlintro -- a brief introduction and overview of Perl".

    -- Ken

      Hi Vinoth and Ken, Actually my requirement is there are two files

      F1,F2 F1 has data NAMES ** name1 name2 ADDRESS street1 street2 PHONE ** num1 is num2 is F2 has data name1 sirname1 street1 housenumber 1 num1 is 8784794 num2 is 9888948 street2 housenumber23 name2 sirname2

      so i read each line in F1 and see if its mandatory(ends with (**) then under that heading i take the values and its corressponding complete value is taken from F2 so finally what i should get is

      NAMES name1 sirname1 NAMES name2 sirname2 PHONE num1 is 8784794 PHONE num2 is 9888948
      Thanks , my code is
      #! usr/bin/perl use strict; use warnings; my $line; my $str; use diagnostics; open my $file_one,'<','F1' or die "unable to open"; while(defined($line=<$file_one>)) { chomp($line); if ($line =~m/(\*\*)/) { $str = $line ; # print " $str \n"; } else { open my $file2,'<','F2' or die "unable to open "; while(defined(my $line2=<$file2>)) { if($line2=~m/$line/) { print " line : $str line2: $line2\n"; } } close($file2); } }

      its giving error

      Invalid [] range "=-," in regex; marked by <-- HERE in m/ 144 x Lc +b (P CAL_LCBMS [CAL_LCBMS] T lcb I [ACT=-, <-- HERE NCLK=chpl::ec0+clk, FORCE_T=-, SG=chpl::ec0+sg+region1+no_l +cc+plat_flush_nto1, THOLD_B=chpl::ec0+sl_thold+ab st+region1+no_lcc, MPW1_B=-, MPW2_B=-, DLY_LCKR=-, DLY0=chpl::ec0+time ++region1+no_lcc+slat, DLY1=chpl::ec0+time+region1 +no_lcc+slat, PW0=chpl::ec0+time+region1+no_lcc+slat, PW1=chpl::ec0+ti +me+region1+no_lcc+slat, PW2=chpl::ec0+time+region 1+no_lcc+slat] E [SG=OR(chpl::ec0+lbist_ary at ./stest line 21, <$file +2> line 1. at ./stest line 21
      where line 21 is the pattern matching statement if($line2=~m/$line/)

        Firstly, please put your error output in <code>...</code> tags. Does what you've posted there look the same as the error message you received?

        When posting, before hitting the [ create ] button, keep editing then hitting the [ preview ] button until your post accurately reflects the information you're attempting to communicate. When updating a post, there's no [ preview ] button; you need to keep editing then hitting the [ update ] button.

        The input data you described looks nothing like what you're reading. Did you open the correct file?

        The data you've read into $line starts off something like (my best guess at reconstructing it):

        144 x Lcb (P CAL_LCBMS [CAL_LCBMS] T lcb I [ACT=-, NCLK=chpl::ec0+clk +, ...

        That (along with all the text that follows it) contains many characters that have special meanings within a regex. A character class is specified within square brackets (i.e. [...]). The "[ACT=-," part of $line starts a character class which includes all the charcters in the range "=-,"; however, ord('=') == 61 and ord(',') == 44, so the start of that range is after its end and, therefore, invalid.

        That explains the error which would have looked something like:

        Invalid [] range "=-," in regex; marked by <-- HERE in m/ 144 x Lcb (P CAL_LCBMS [CAL_LCBMS] T lcb I [ACT=-, <-- HERE ...

        While I suspect this is a mistake on your part (e.g. you're reading the wrong file), if you want to interpolate data like that into a regex, you'll need to do something like:

        /\Q$line/

        See quotemeta for details.

        -- Ken

Re: Nested While loop not working
by vinoth.ree (Monsignor) on Mar 11, 2014 at 09:19 UTC

    As choroba suggested, use three argument open() with die

    There are two forms of the open() function in Perl 5. The modern version takes three arguments: the filehandle to open or vivify, the mode of the filehandle, and the name of the file.

    The legacy version has two arguments, only the filehandle and the name of the file. The mode of the file comes from the filename; if the filename starts (or ends) with any of several special characters, open() parses them off and uses them.

    If you accidentally use a filename with those special characters with the two-arg form of open(), your code will not behave as you expect. This is especially a problem if you are not careful about sanitizing user input, and if any user input ever becomes part of a filename. Ex.

    open my $fh, ">$filename" # INSECURE CODE; do not use or die "Can't write to '$filename': $!\n";
    While this code appears to open $filename for writing, an insecure $filename could start with > to force appending mode, or - to open STDOUT. Likewise, code without any explicit mode in the second and final parameter is susceptible to any special mode characters.

    Extracting file modes into a separate parameter to this function prevents Perl from parsing the filename at all and removes the possibility for this unintentional behavior. As Damian Conway has mentioned, using a separate file mode parameter also makes the intention of the code clearer

    open my $fh, '>', $filename # safer and clearer or die "Can't write to '$filename': $!\n";

    The modern version of this code is safer and clearer.


    All is well

      Hi Vinoth, I used the three arg open syntax but it doesnt help ..

        What happens?
Re: Nested While loop not working
by sivaramraj (Initiate) on Mar 11, 2014 at 12:40 UTC
    Try this code ;) Have to come out of the second loop after the line has been printed so that the line will be queued out. it can be done using... last;
    #!/usr/bin/perl use strict; open(FILE1,"abc"); open(FILE2,"def"); while (my $name1=<FILE1>) { chomp($name1); while (my $name2=<FILE2>) { chomp($name2); print "Line1: $name1 | Line2: $name2 \n"; last; } } close(FILE1); close(FILE2);