daffodil
daffodil

Reputation: 197

Find file that does not contain specific string

I want to find file that does not contain the specific string? The listed file is like below

../../../experiment/fileA.txt (contain word 'Book')
../../../experiment/fileB.txt (contain word 'Book')
../../../experiment/fileC.txt (do not contain word 'Book')
../../../experiment/fileD.txt (contain word 'Book')

Here is my code

use strict;
use warning;

my $dirname = "../../../experiment/";
my $keyword = "Book";
my @result;

my $find_file = sub {
    my $F = $File::Find::name;
    if ($F =~ /txt$/) {
       open my $in, "<", $F or die $!;
       while(<$in>) {
          if (/\Q$keyword\E/){
             next;
          }else{
             push @result, $F;
             return;          
          }
      }
   }  
};

find ({ wanted => $find_file, no_chdir=>1}, $dirname );
foreach my $result (@result){
   chomp $result;
   $result =~ s{.*/}{};
   print "$result\n";
}   

But it seem does not work. It display all file whether it has the $keyword or not. I only want it to display only if the file does not have the $keyword

Upvotes: 1

Views: 168

Answers (3)

Grinnz
Grinnz

Reputation: 9231

Path::Iterator::Rule makes tasks like this really simple. As a side note, I would recommend resolving the directory to an absolute path before iterating.

use strict;
use warnings;
use Cwd 'abs_path';
use File::Basename;
use Path::Iterator::Rule;

my $dirname = abs_path "../../../experiment/";
my $keyword = "Book";

my $rule = Path::Iterator::Rule->new->not_dir->name(qr/txt$/)->not_line_match(qr/\Q$keyword\E/);
my $next = $rule->iter($dirname);
while (defined(my $file = $next->())) {
  print basename($file), "\n";
}

Upvotes: 1

zdim
zdim

Reputation: 66881

There's a simple logic error. The code goes through lines of each file

while (<$in>) {
    if (/\Q$keyword\E/){
        next;
    } else {
        push @result, $F;
        return;          
    }
}

and as soon as any one line doesn't have $keyword it adds the file to @result.

You need to check all lines and if $keyword is never found only then add a file. The easiest way to do this is to return from the sub as soon as the thing is found

while (<$in>) {
    return if /\Q$keyword/;
}

push @result, $F;

Upvotes: 4

Andy Lester
Andy Lester

Reputation: 93676

This doesn't address your code, but I'd like to point out that with the grep command on any Linux system you can do exactly what it looks like you're trying to do with this command:

grep -L Book -R ../../../experiment/

Upvotes: 2

Related Questions