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
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
- The results are stored in
@matches
, so to get the last one, theprint
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>