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

I would like to open multiple files and parse through them at the same time. The reason I'm doing this is to edit logs, but I need to be able to open multiple and edit them all because the data from one log file can spill over into the next log file. I would like to open them like this:
open( FILE1, "path here" ); open( FILE2, "path here" ); open( FILE3, "path here" );
I know that with one file open I can easily go through it by looping like this:
while( $lines = <FILE1> ) { "Do fun stuff here" }
So a more precise version of my question is whether or not I can do something like that while loop but with lots of files? Any help would be appreciated.

Replies are listed 'Best First'.
Re: replacing text in multiple files
by aaron_baugher (Curate) on Apr 13, 2012 at 22:07 UTC

    It sounds like you'd be fine with processing them one at a time, not all at once. In that case, just wrap your while loop in another loop that goes through the files:

    my @files = qw( /path/to/file1 /path/to/file2 /path/to/file3 ); for my $file (@files){ open my $fd, '<', $file or die $!; while(my $line = <$fd>){ # do stuff with the next line } close $fd; }

    Aaron B.
    My Woefully Neglected Blog, where I occasionally mention Perl.

Re: replacing text in multiple files
by Eliya (Vicar) on Apr 13, 2012 at 22:03 UTC

    Use <> (instead of <FILE1>) and specify the files as command line arguments (or manually put them in @ARGV).

Re: replacing text in multiple files
by graff (Chancellor) on Apr 14, 2012 at 02:49 UTC
    If you have (a version of) the unix/linux "cat" utility, you can use the "diamond" operator as suggested by Eliya's initial reply, and pipe the concatenated set of files to your script's STDIN -- for that matter, you can also just print to STDOUT, and use redirection to a file on the command line:
    cat *.log | your_script > modified.log-data
    With that sort of usage, you don't need to worry about opening or closing files in your code; just read, do stuff, and print:
    #!/usr/bin/perl use strict; while (<>) { # do stuff here, then... print; }
      cat *.log | your_script > modified.log-data

      Why use cat when Perl can do it all by itself?  With the added benefit of $ARGV letting you know which file you're working on, and being able to do in-place edits via -i / $^I:

      $ cat *.log bar1 bar2 bar3 baz1 baz2 baz3 foo1 foo2 foo3 $ perl -ne 'print "$ARGV: $_"' *.log bar.log: bar1 bar.log: bar2 bar.log: bar3 baz.log: baz1 baz.log: baz2 baz.log: baz3 foo.log: foo1 foo.log: foo2 foo.log: foo3 $ cat *.log | perl -ne 'print "$ARGV: $_"' -: bar1 -: bar2 -: bar3 -: baz1 -: baz2 -: baz3 -: foo1 -: foo2 -: foo3 $ perl -i -ne 'print ucfirst $_' *.log $ cat *.log Bar1 Bar2 Bar3 Baz1 Baz2 Baz3 Foo1 Foo2 Foo3

      (note to the OP:  -n is the short "command line" version of saying while (<>) { ... } — see perl -h )

Re: replacing text in multiple files
by Anonymous Monk on Apr 13, 2012 at 22:23 UTC
    # Edit-in-place in multiple files - one file at the time { local $^I = q{}; local @ARGV = @files; while(defined(my $line = <>)){ # do something with $line } continue { print $line; } }
    or
    # Read multiple lines from multiple files at the same time my @files = @ARGV; my @fh; my $i = 0; foreach my $file (@files) { -f -r $file or next; open $fh[$i++], '<', $file or die "Cannot open $file: $!"; } while (1) { my @lines; foreach my $i (0 .. $#fh) { ref $fh[$i] eq 'GLOB' or next; push @lines, scalar readline $fh[$i]; if (eof $fh[$i]) { close $fh[$i]; $fh[$i] = undef; } } @lines or last; foreach my $line (@lines) { # do something with $line } }

      How can Anonymous Monks edit their nodes??

      I'm pretty confident that the first time I saw this reply, there was only the part up to the "or" ...

        What you saw was database hiccup
Re: replacing text in multiple files
by Anonymous Monk on Apr 14, 2012 at 02:36 UTC
Re: replacing text in multiple files
by brayk1990 (Novice) on Apr 16, 2012 at 16:24 UTC
    First of all I want to thank everyone for helping with the first error I was having. I was able to get the code cycling through the files, however now I'm running into an error doing a regex substitutions.
    #Find the CHAN pair if( $UNID[1] eq $UNID[$x] ) { #Temporary variable to store the CHAN $channel2 = $CHAN[$x]; #Creates a loop counter $y = 1; #Tracks if the changes have been complete $complete = 0; #Search the files for the instancs of the CHAN while( ( $y < scalar( @FILES ) ) && ( $complete == 0 ) + ) { #Open the file for replacement open $fd, '<', $FILES[ $y ]; #Creates a backup of the original file $^I = '.bac'; @file = <$fd>; seek $fd, 0, 0; print "$channel1 and $channel2\n"; foreach $file ( @file ) { $file =~ s/$channel2/$channel1/ or die $!; } #Close the file that was searched close $fd; $y++; }#End replacing while #Remove the used entries from the array delete $CHAN[1]; delete $UNID[1]; delete $CHAN[$x]; delete $UNID[$x]; #Force the loop to end $found = 1; }#End pair find if
    For some reason the line containing the studstitution errors out saying the variables are uninitialized. But I can put a print statement directly before them and that will print the values just fine. If I a use an or die statement I recieve an error just saying that the program died. Any help would be greatly appreciated. Thank you.