Home > Blockchain >  Find last occurrences of a string from multiple files in a directory using perl
Find last occurrences of a string from multiple files in a directory using perl

Time:12-15

In a directory have multiple file . from all that file i have to find the last occurrence of a string and print that line into a result.txt file. Let assume the files are like demo*.txt.

And the string i have to find is "FREQ" . The code i have tried is as follows :

    for ( glob("demo*.txt"  ) ) {
        my $xm = $_;
        open my $fh, '<', $xm;
        my $pat = "FREQ" ;
        while(my $asa =  <$fh>) {
            my @last = grep(/FREQ/, $asa);
        }
     } 
     print " grep : @last\n";

I have tried this code but this giving nothing and I cant able to find the mistake i am making.

CodePudding user response:

As @vkk05 suggests, you need to add use strict & use warnings to your code

use strict;
use warnings;

for ( glob("/tmp/demo*.txt"  ) ) {
    my $xm = $_;
    open my $fh, '<', $xm;
    my $pat = "FREQ" ;
    while(my $asa =  <$fh>) {
        my @last = grep(/FREQ/, $asa);
    }
} 

print " grep : @last\n";

When I run that I get

Possible unintended interpolation of @last in string at /tmp/fred.pl line 15.
Global symbol "@last" requires explicit package name (did you forget to declare "my @last"?) at /tmp/fred.pl line 15.
Execution of /tmp/fred.pl aborted due to compilation errors.

The problem is the my @last line. You are defining @last in the scope of the while loop. That means the variable @last gets deleted once the while loop exits.

Moving the definition of @last to outside the while scope and moving the print line to run immediately after the while loop gives this code

use strict;
use warnings;


for ( glob("/tmp/demo*.txt"  ) ) {
    my $xm = $_;
    open my $fh, '<', $xm;
    my $pat = "FREQ" ;
    my @last;
    while(my $asa =  <$fh>) {
        @last = grep(/FREQ/, $asa);
    }

    print " grep : @last\n";
} 

and assuming a test file /tmp/demo1.txt

$ cat /tmp/demo1.txt 
abc
FREQ 123
FREQ 456

running the script gives

 grep : FREQ 456

Finally, the use of grep in this context is confusing -- it is intended to be used when iterating through a list of values, rather than a single entry as in this case. Although the code works fine with the way you are using grep, a more perl-idiomatic solution that uses grep would be

use strict;
use warnings;

my $pat = "FREQ" ;

for my $xm ( glob("/tmp/demo*.txt"  ) ) {
    open my $fh, '<', $xm
        or die "Cannot open '$xm': $!";

    my @matches = grep { /$pat/ }
                  <$fh>;

    print " file $xm : $matches[-1]\n";
} 

Points to note

  1. grep is used here in a proper list context, along with <$fh> to walk the file and match all lines that include the pattern stored in $pat
  2. The results are stored in @matches, so to get the last one, the print statement uses $matches[-1] to index the final entry in @matches.

CodePudding user response:

If this is a one time only task I would use a simple one-liner like this.

Create four test files. The last is empty:

echo -e "FREQ\nline 2\nFREQ again\nline4"         > demo1.txt
echo -e "FREQUENT\nline 2 in demo2\nShrek\nXFREQ here" > demo2.txt
echo -e "nothing to see\nnothing to see!"          > demo3.txt 
touch demo4.txt

Run:

perl -E '@f=@ARGV; /FREQ/ and $L{$ARGV}=$_ while<>; print "Last FREQ line in $_: ".($L{$_}//"<none>\n") for @f' demo*.txt | tee result.txt

Output:

Last FREQ line in demo1.txt: FREQ again
Last FREQ line in demo2.txt: XFREQ here
Last FREQ line in demo3.txt: <none>
Last FREQ line in demo4.txt: <none>
  • Related