Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to pass an anonymous sub to Find::File

I know I can do this as an expression modifier:

#!/usr/bin/perl -w
use strict;
use File::Find;

sub file_find{
    my ($path,$filter) = @_;
    find(sub {print $File::Find::name."\n" if /$filter/}, $path);   
}
file_find($newdir,'\.txt');

or this which is less readable:

find(sub {if(/$filter/){print $File::Find::name."\n"}}, $path);

But if I wanted to do something like this, how can I do it?

sub file_find{
    my ($path,$filter) = @_;

    find(\&print, $path);

    sub print {
        if(/$filter/){ #Variable $filter will not stay shared
            print $File::Find::name."\n";
        }
    }   
}
file_find($newdir,'\.txt')

I get 'variable will not stay shared'. I believe I'm supposed to make it an anonymous sub:

my $print = sub {
    if(/$filter/){
        print $File::Find::name."\n";
    }
}

But then I don't know how to pass the reference to the find sub. Perhaps it's somthing silly I'm missing.

Edit: Never mind, this seems to work:

sub file_find{
    my ($path,$filter) = @_;    

    my $subref = sub{
        if(/$filter/){
            print $File::Find::name."\n";
        }
    };

    find($subref,$path);    

}
file_find($newdir,'\.txt');

I had to push the find sub to the bottom! Man I feel so dumb :)

like image 477
Mack Avatar asked Dec 07 '25 11:12

Mack


1 Answers

I would separate the subs apart (and rename the print() one as it conflicts with the built-in with the same name!), then you can do something along these lines (if I'm understanding what you want correctly):

use warnings;
use strict;

use File::Find;

file_find('.', '.txt');

sub file_find{
    my ($path,$filter) = @_;
    my @files = find(sub {my_print($filter)}, $path);
}
sub my_print {
    my $filter = shift;

    my $fname = $File::Find::name;

    if($fname =~ /$filter/){
        print "$fname\n";
    }
}

However, with that said, File::Find::Rule can make these things very, very easy (particularly handling the file filters as it handles regex natively):

use warnings;
use strict;

use File::Find::Rule;

my $filter = '*.txt';
my $dir = '.';

my @files = File::Find::Rule->file()
                            ->name($filter)
                            ->in($dir);

print "$_\n" for @files;
like image 106
stevieb Avatar answered Dec 10 '25 04:12

stevieb



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!