Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

In Perl, how can I make two passes over all the files specified on the command line via the diamond operator?

Tags:

perl

If i have a text file and i want to run two types of operations, but each operation must read each line of the text separately from the other. The only way i know how to do it is

open out,(">>out.txt");
while (<>){
    #operation one
}
while (<>){
    #operation two
}
close out;

but this will run only on the first while, in which the operation runs fine, but the second one will not be complete because the second while(<>) does not actually re-read the file but tries to continue from where the first while left. Which is at the end of the file. So is there another way? Or is there a way to tell the second while to start again at the beginning?

like image 585
Constantine Avatar asked Jan 17 '26 02:01

Constantine


2 Answers

Given you mention in a comment:

 perl example.pl text.txt 

The answer is - don't use <> and instead open a filehandle.

my ( $filename ) = @ARVG;

open ( my $input, "<", $filename ) or die $!;

while ( <$input> ) { 
    print; 
}

seek ( $input, 0, 0 ); 

while (  <$input> ) { 
    #something else
}

Alternatively, you can - assuming test.txt isn't particularly large - just read the whole thing into an array.

my @input_lines = <$input>;
foreach ( @input_lines ) { 
   #something
}

If you want to specify multiple files on the command line, you can wrap the whole thing in a foreach loop:

foreach my $filename ( @ARVG ) { 
    ## open; while; seek; while etc. 
}
like image 141
Sobrique Avatar answered Jan 19 '26 18:01

Sobrique


Couldn't you simply use the following?

while (<>) {
   operation1($_);
   operation2($_);
}

If not, then I'm assuming you need to process the content of all the files using one operation before it's process by the other.

<> reads from the files listed in @ARGV, removing them as it opens them, so the simplest solution is to backup @ARGV and repopulate it.

my @argv = @ARGV;
while (<>) { operation1($_); }
@ARGV = @argv;
while (<>) { operation2($_); }

Of course, it will fail if <> reads from something other than a plain file or a symlink to a plain file. (Same goes for any solution using seek.) The only to make that work would be to load the entire file into temporary storage (e.g. memory or a temporary file). The following is the simplest example of that:

my @lines = <>;
for (@lines) { operation1($_); }
for (@lines) { operation2($_); }
like image 43
ikegami Avatar answered Jan 19 '26 18:01

ikegami



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!