Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Perl: How to stop File::Find entering directory recursively?

Tags:

perl

I was looking at Perl's File::Find module and tried it in the following way:

#!/usr/bin/perl

use warnings;
use strict;

use File::Find;

find({wanted => \&listfiles,
        no_chdir => 1}, ".");


sub listfiles{
    print $File::Find::name,"\n";
}

Now When I run it I get the below output:

Noob@Noob:~/tmp$ perl test.pl 
.
./test.txt
./test.pl
./test1.txt
./hello
./hello/temp.txt

Now, I was thinking that by setting no_chdir=>1 I will make my code to not enter any directory if it came across one. But the output clearly shows that my code is entering hello directory and listing its files.

So, how do I change my code to behave like ls and not enter any directory. Also I am getting ./ in front of my file/directory names can that be removed?

I am using Perl 5.14.

like image 594
RanRag Avatar asked Nov 27 '22 05:11

RanRag


1 Answers

$File::Find::prune can be used to avoid recursing into a directory.

use File::Find qw( find );

my $root = '.';
find({
   wanted   => sub { listfiles($root); },
   no_chdir => 1,
}, $root);

sub listfiles {
   my ($root) = @_;
   print "$File::Find::name\n";
   $File::Find::prune = 1  # Don't recurse.
      if $File::Find::name ne $root;
}

You can set prune conditionally if you so desire.

use File::Basename qw( basename );
use File::Find     qw( find );

my %skip = map { $_ => 1 } qw( .git .svn ... );

find({
   wanted   => \&listfiles,
   no_chdir => 1,
}, '.');

sub listfiles {
   if ($skip{basename($File::Find::name)}) {
      $File::Find::prune = 1;
      return;
   }

   print "$File::Find::name\n";
}

no_chdir is not necessary — it has nothing to do with what you are trying to do — but I like what it does (prevents changes to the cwd), so I left it in.

like image 96
ikegami Avatar answered Nov 30 '22 23:11

ikegami