Search code examples
fileperlfindsubdirectory

Search for specific files in folder without subfolders using perl


i want to search for specific file inside a Folder but not in the subfolder of this folder. Following Structure is given:

FolderA
|
|__SubFolder1
    |__File1.txt
    |__File2.txt
|
|__File3.txt
|__File4.cmd
|__File5.txt

Now i am searching all txt files in Folder A like this:

sub GetFiles()
{
  my @DIRS = (FolderA);
  find ( \&searchFiles, @DIRS );
  for my $myfile (%MYFILES) {
    ####do something with the files###
  }
}

sub searchFiles() 
{
  return unless /\.txt/;
  return unless -f $File::Find::name;

  $MYFILES{$File::Find::name} = {'NAME'=> $File::Find::name }
}

The Code looks good to me but I always get all .txt Files, even those from Subfolder. Actual result is like this:

File1.txt File2.txt File3.txt File5.txt

But I want only

File3.txt File5.txt

Where did I the mistake?


Solution

  • You could use File::Find.

    use File::Find qw( find );
    
    my @dir_qfns = qw( FolderA );
    
    find(
       sub {
          # Don't do anything for a base dir.
          return if $_ eq '.';
    
          # Don't recurse.
          $File::Find::prune = 1;
    
          stat($_) 
             or do {
                warn("Skipping \"$_\": Can't stat: $!\n");
                next;
             };
    
          -f _
             or return;
          /\.txt\z/
             or return;
    
          # ... do something with $File::Find::name/$_ ...
       },
       @dir_qfns,
    );
    

    It's far simpler with File::Find::Rule. (Isn't it always?)

    use File::Find::Rule qw( );
    
    my @dir_qfns = qw( FolderA );
    
    for my $qfn (
       File::Find::Rule
       ->mindepth(1)
       ->maxdepth(1)
       ->file
       ->name("*.txt")
       ->in(@dir_qfns)
    ) {
       # ... do something with $qfn ...
    }
    

    You could also do it using glob.

    my @dir_qfns = qw( FolderA );
    
    for my $dir_qfn (@dir_qfns) {
       for my $fn (glob("\Q$dir_qfn\E/*.txt")) {
          my $qfn = "$dir_qfn/$fn";
          stat($qfn) 
             or do {
                warn("Skipping \"$qfn\": Can't stat: $!\n");
                next;
             };
    
          -f _
             or next;
    
          # ... do something with $fn/$qfn ...
       }
    }
    

    (Note that using quotemeta (e.g. via \Q..\E as shown above) is not a proper way of generating a glob pattern from a directory name on Windows.)