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

Hi, this is a slight follow on to a question posted yesterday. I have a list of files stored into an array which i need to access one at a time and do something with it!
@files = grep /^output\d+$/, <output*>; foreach $file (@files) { open (IN, "<$file"); while ($input = <IN>) { print "$file\n"; ($x, $y, $z, $sum) = split (/\s+/, $input); $total += $sum; $i++; $div = $total/$i; $sqrt = sqrt($div); print "$total\n"; open (OUT2, ">RMSD$file"); print OUT2 $sqrt; } }
Problem is that the wrong answer comes out, and calling print "$file\n"; shows that each of the files are called twice??? any suggestions? Thanks,

Replies are listed 'Best First'.
Re: files stored in an array
by Enlil (Parson) on Aug 08, 2004 at 16:40 UTC
    Does there happen to be more than one line in each file. If so then print "$file\n" will be executed once per line. Try moving that line outside the while loop to see how many times the files are called.

    Second, since I am not completely sure of what you want. My guess is that you want each files input independent of the other. (in other words you want the variables inside the while loop initialize before you do anything with them. My guess (and only a guess) is you want something like the following (not tested):

    use strict; use warnings; my @files = grep /^output\d+$/, <output*>; foreach my $file ( @files ) { open (IN, "<$file") or die "could not open $file: $!"; print "$file\n"; my ($total,$i) = (0,0); #initialize to zero for each file while ( my $input = <IN> ){ #sine you don't seem to be using $x, $y, $z anyhow my $sum = (split /\s+/,$input)[3]; $total += $sum; $i++; my $div = $total/$i; my $sqrt = sqrt($div); print "$total\n"; open (OUT2, ">RMSD$file") or die "could not open RMSD$file: $!"; print OUT2 "$sqrt\n" } }

    HTH

    -enlil

      thanks Enlil this does the job nicely. At least i was almost on the "ball"! :-)
Re: files stored in an array
by davido (Cardinal) on Aug 08, 2004 at 16:33 UTC

    I don't see why files would be included twice. Why don't you start out by printing the content of @files to see if it contains duplicates?

    Also, your script won't compile under strictures. And it uses bare filehandles instead of lexically scoped ones. And it does that without ever closing any files after use. It also never checks to be sure that a file got properly opened.

    I've taken a minute or two to alter your code just enough to get it to pass strictures, and to explicitly close filehandles. I've also used lexical filehandles, which actually would close themselves when they fall out of scope, so my 'close' lines are somewhat redundant. I've also added the classical "or die..." mechanism to your file opens, so that if a file is failing to open you'll know about it.

    Here's the code...

    use strict; use warnings; my @files = grep /^output\d+$/, <output*>; my ( $total, $i ); foreach my $file (@files) { open ( my $in, "<$file" ) or die "Couldn't open $file: $!\n"; while ( my $input = <$in>) { print "$file\n"; my ($x, $y, $z, $sum) = split (/\s+/, $input); $total += $sum; $i++; my $div = $total/$i; my $sqrt = sqrt($div); print "$total\n"; open ( my $out2, ">RMSD$file") or die "Couldn't open RMSD$file: $!\n"; print $out2 $sqrt; close $out2; } close $in; }

    Update: I missed the mark on the actual problem, and others were correct in finding that you're printing to the output file once per line. You're also opening the output file once per line... it hasn't been mentioned, but each time you open the file for output in the way you are, it clobbers whatever the file contained previously. That's kinda a mess. ...my example didn't fix that either, but it's certanly worth mentioning.


    Dave

      And it uses bare filehandles instead of lexically scoped ones. And it does that without ever closing any files after use.
      There are worse things in the world than that. And as a matter of fact it does close every file but the last one. Lexically scoped filehandles are neat, and should definitely be used in a subroutine or a module, but I don't see pressing need to convert newbies to their use in the main code of a script. I also am not sure I see the point of doing an explicit close unless you want to take some action if it returns an error.
Re: files stored in an array
by saintmike (Vicar) on Aug 08, 2004 at 16:40 UTC
    Your code opens up a new output file for every line in all of the input files. Is this what you're intending?

    A couple of general comments:

    • If something doesn't work as expected, let the code print out messages which indicate what's going on. In your case, put print statements into the foreach and while loops showing files and data processed.
    • Use use strict; use warnings to enable perl to help you track down typos.
    • Check the return code of functions like open.