Beefy Boxes and Bandwidth Generously Provided by pair Networks
Think about Loose Coupling
 
PerlMonks  

Open in for loop/array structure

by igotlongestname (Acolyte)
on Jun 02, 2008 at 22:09 UTC ( #689767=perlquestion: print w/replies, xml ) Need Help??

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

I am writing a simple script that I want to read in an array of input file names, then loop through each file ... performing some operations and generating an output file for each corresponding input file. I have a script that is "close" to working (at least I believe it's close).

When attempting to execute, the script gets through the first iteration ($k=0, code attached below) just fine, generating the output file "ND_out-02-00.txt", but as it increments to $k=1, I get the following error:

"print() on closed filehandle OUT at isotopes-p7.perl line 17, <GEN0> line 46079. Use of uninitialized value in scalar chomp at isotopes-p7.perl line 19, <GEN0> line 46079. Use of uninitialized value in concatenation (.) or string at isotopes-p7.perl line 20, <GEN0> line 46079. Can't read the source:No such file or directory at isotopes-p7.perl line 20, <GEN0> line 46079."

#!/usr/local/bin/perl -w use IO::File; my $file = IO::File->new; @FN=("out-02-00.txt","out-02-01.txt","out-02-02.txt","out-02-03.txt"," +out-02-04.txt","out-02-05.txt","out-02-06.txt","out-02-07.txt","out-0 +2-08.txt","out-02-09.txt", "out-02-10.txt","out-02-11.txt","out-02-12.txt","out-02-13.txt", +"out-02-14.txt","out-02-15.txt","out-02-16.txt","out-02-17.txt","out- +02-18.txt", "out-02-20.txt","out-02-21.txt","out-02-22.txt","out-02-23.txt", +"out-02-24.txt","out-02-25.txt","out-02-26.txt","out-02-27.txt","out- +02-28.txt", "out-02-30.txt","out-02-31.txt","out-02-32.txt","out-02-33.txt", +"out-02-34.txt","out-02-35.txt","out-02-36.txt","out-02-37.txt","out- +02-38.txt"); $FN=@FN; for($j=0; $j<$FN; $j++){ print "$FN[$j]\n"; } for($k=0; $k<$FN; $k++){ print "$FN[$k]\n"; $filename = <$FN[$k]>; chomp ($filename); $file->open("< $filename") or die("Can't read the source:$!"); open(OUT, ">ND_$filename"); select (OUT); @BU=(); @MA1=(); @MA2=(); until ($file->eof) { my $line = $file->getline(); if ($line =~ /K-INF,LEAK \(B2/) { my @col3 = split(qr/\s+/s, $line); #split on whitespace push(@BU,"$col3[14]"); } elsif($line =~ /0 EID: 93237/) { $line = $file->getline(); chomp($line); @col1 = split(qr/\s+/s, $line); push(@MA1,"$col1[3] $col1[4] $col1[5] $col1[6] $col1[7] $col +1[8] $col1[9] $col1[10] $col1[11]"); } elsif ($line =~ /0 EID: 95241/) { $line = $file->getline(); chomp($line); @col2 = split(qr/\s+/s, $line); push(@MA2,"$col2[3] $col2[4] $col2[5] $col2[6] $col2[7] $col +2[8] $col2[9]"); } } # end of until for($i=1; $i<=58; $i++){ print "$BU[$i-1] $MA1[$i-1] $MA2[$i-1]\n"; } close(OUT); }
I know the file names are correct, and in the directory and that they are being accessed in that name sequence since my first for loop simply tests that the names are as expected. I think my problem may be the recursive open/close statements for either the input or output files (or both). Anybody know what's going on here? Thanks! ~Jack

Replies are listed 'Best First'.
Re: Open in for loop/array structure
by apl (Monsignor) on Jun 02, 2008 at 23:15 UTC
    First add use strict; use warning;

    After you fix the problems they report, post again... (And add comments as to which is line 17, 20, etc.)

Re: Open in for loop/array structure
by pc88mxer (Vicar) on Jun 02, 2008 at 23:37 UTC
    As apl says, adding use strict and use warnings is always a good practice.

    I am curious about this fragment:

    print "$FN[$k]\n"; $filename = <$FN[$k]>; chomp ($filename); $file->open("< $filename") or die("Can't read the source:$!");
    The expression <$FN[$k]> reads from the file handle $FN[$k]. Do your files out-02-00.txt, etc. contain a file name or do they contain data? If the latter, I think you want just $filename = $FN[$k];.

    Update: The following curiosity has been cleared up by duff below.

    The curious part is that my testing shows that $filename is actually being set to $FN[$k] (cygwin-perl 5.8.8). However, this supposedly equivalent code sets $filename to undef:

    ... $filename = readline($FN[$k]); ...
    Update: Some more testing shows that if $f is the path of an existing file, then <$f> returns $f (assuming that $f has not been used as a file handle. Otherwise it returns undef. Ver interesting...
      The expression <$FN$k> reads from the file handle $FN$k

      I don't think so. If the text inside <> isn't a simple scalar then the diamond operator turns into glob

        Oh that makes sense now - forgot about the glob operator.
      Thank you all so much for your help, the simple removal of the <>'s fixed the problem. I'm new enough to not totally follow why filehandles caused the problem, yet the code worked on the first run through (the error version with filehandles included) and not on subsequent iterations, but I'm happy it works.

      Also, I added the "use strict" and got a trillion warnings, so removed it to verify completion which it did, I'll work on making it strict friendly too.

      Final question if someone has an understanding. This doesn't adjust my calculations at all, but is interesting for me in regards to better understanding. The first time through the for loop ($k=0), the 'print "$FN$k\n"' line prints the correct name (out-02-00.txt), but from then ($k>0) on I get an error that says "print() closed on filehandle OUT at isotopes-p7.perl line 14", which is the print line I just referred to. Is this because I "close(OUT)" at the bottom of the for loop and this is affecting the next iterations print statement until a new "OUT" file is opened? Any way to circumvent this? (I would just move the open(OUT) statement up, but I need $filename to correctly name it). Can I open a dummy out file for the time being or is there specific nomenclature for opening to terminal? I'll quit hazarding guesses and wait for an answer. Thanks again, any thoughts are welcome.

        yet the code worked on the first run through (the error version with filehandles included) and not on subsequent iterations, but I'm happy it works.

        You weren't using file handles. As already explained, you were using glob. And glob in scalar context acts as an iterator. The first time it's called, it returns the first match. The second time it's called, it returns the second match. And so on. When it's done, it returns undef. I've demonstrated that earlier in this thread.

        The first time you called <$FH[$k]> (when $k==0), it returns the first result for $k==0.
        The second time you called <$FH[$k]> (when $k==1), it returns the second result for $k==0 (undef).

        but from then ($k>0) on I get an error that says "print() closed on filehandle OUT at isotopes-p7.perl line 14"

        You told print to output to OUT (select (OUT);), but you closed OUT. Personally, I would remove the call to select and change
        print "$BU[$i-1] $MA1[$i-1] $MA2[$i-1]\n";
        to
        print OUT "$BU[$i-1] $MA1[$i-1] $MA2[$i-1]\n";
        I don't like using select. As you've encountered first hand, it introduces problems too easily.

Re: Open in for loop/array structure
by jwkrahn (Monsignor) on Jun 03, 2008 at 01:50 UTC

    I would try running it like this:

    #!/usr/local/bin/perl use warnings; use strict; my @FN = map "out-02-$_.txt", '00' .. '18', 20 .. 28, 30 .. 38; for my $filename ( @FN ) { print "$filename\n"; open my $FILE, '<', $filename or die "Can't open $filename: $!"; open my $OUT, '>', "ND_$filename" or die "Can't open ND_$filename: + $!"; my ( @BU, @MA1, @MA2 ); while ( my $line = <$FILE> ) { if ( $line =~ /K-INF,LEAK \(B2/ ) { push @BU, ( split ' ', $line )[ 14 ]; } elsif ( $line =~ /0 EID: 93237/ ) { push @MA1, join ' ', ( split ' ', <$FILE> )[ 3 .. 11 ]; } elsif ( $line =~ /0 EID: 95241/ ) { push @MA2, join ' ', ( split ' ', <$FILE> )[ 3 .. 9 ]; } } for my $i ( 0 .. 57 ) { print $OUT join( ' ', $BU[ $i ] || '', $MA1[ $i ] || '', $MA2[ + $i ] || '' ), "\n"; } }
      jw, Thanks for the suggestion, I'll put it in and give it a shot see how it works. It's pretty much guaranteed to be "better" than what I've got, in terms of concise-ness and "correctness" or whatever. Thanks for taking the time to help me out, it's really appreciated!

      ~Jack

      Update ... I put it in and ran, and it ran beautifully. One question, if you can give me a pointer. In filling the @FN array, you use the map command and the $_ character, I think I understand that alright, but why did you have to put the first chunk of numbers in single quotes (i.e. '00 .. '18'), but not the rest of them? Is either convention acceptable or is there something specific here?

      Also, in the for loop, is it automatic convention that if an array with a scalar name before it (in this case calling $filename in the loop, with the looping parameter being @FN) is accessed, the length of the loop is the length of the array, and the scalar is automatically updated to be each member of the array, starting at 0 and going to the last array point? Does that make sense or is it too wordy?

      Just trying to understand exactly how in the for loop, the code knows to use each name in the array. Thanks again!

      ~Jack

        why did you have to put the first chunk of numbers in single quotes (i.e. '00' .. '18'), but not the rest of them?

        I used the quotes because without them perl would remove the leading zeros.

        how in the for loop, the code knows to use each name in the array.

        That is the way that for/foreach loops work.

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://689767]
Approved by Argel
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others examining the Monastery: (3)
As of 2022-10-02 10:45 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?
    My preferred way to holiday/vacation is:











    Results (8 votes). Check out past polls.

    Notices?