bichonfrise74 has asked for the wisdom of the Perl Monks concerning the following question:

Hi,

I have 2 questions on File::Find.

This is the code the works.
#!/usr/bin/perl use strict; use File::Find; my $file; find( \&wanted, '/tmp/test' ); print "$file\n"; sub wanted { $dir = $File::Find::name if ( /hello\.txt/ ); }
My first question is how do I shorten this code, I wanted to do something like this...
... find( \&{ $dir = $File::Find::name if ( /hello\.txt/ ) }, '/tmp/test' );
So, it is complaining that it is not able to create the sub named "".

My second question is how come I don't get any return values from this code?
#!/usr/bin/perl use strict; use File::Find; my $dir = find( \&wanted, '/tmp/test' ); print "$dir\n"; sub wanted { return $File::Find::name if ( /hello\.txt/ ); }

Replies are listed 'Best First'.
Re: 2 Questions on File::Find
by ikegami (Patriarch) on Jul 17, 2009 at 22:07 UTC

    Anonymous subs are created using sub { }.

    Just declare the variable outside of find.

    use File::Find; my $dir; find( sub { $dir = $File::Find::name if ( /hello\.txt/ ); }, '/tmp/test' );

    Unfortunately, find will keep on searching for more matches. You can exit prematurely using die

    use File::Find; my $dir; if (!eval { find( sub { die "match: $File::Find::name\n" if ( /hello\.txt/ ); }, '/tmp/test' ); 1 }) { my $e = $@; die $e if !( ($dir) = /^match: (.*)/ ); }
Re: 2 Questions on File::Find
by psini (Deacon) on Jul 17, 2009 at 22:07 UTC

    First answer:

    I think that what you are trying to do is:

    find( sub { $dir = $File::Find::name if ( /hello\.txt/ ) }, '/tmp/test +' );

    defining an anonymous sub as callback. I don't understand how can your code "work" for you are using strict and $dir is not defined anywhere.

    Second answer:

    File::Find::find does not work so. As per documentation, the return value of the callback function is ignored by find. The correct way to do it is that of your first example.

    Rule One: "Do not act incautiously when confronting a little bald wrinkly smiling man."

Re: 2 Questions on File::Find
by Marshall (Canon) on Jul 17, 2009 at 22:27 UTC
    File::Find is a weird critter as it doesn't have a return value. This is a recursive descent deal that runs a subroutine on every file from starting directory. (note: that a directory name is a file!).

    there is no return value from File::Find, you need to use a "global" var to get this...

    here is example code.....

    #!/usr/bin/perl -w use File::Find; use strict; my @dirs; find (\&dirs_deny_grp_other, $ENV{'HOME'}); print join ("\n",sort @dirs),"\n"; sub dirs_deny_grp_other { return if ! -d || !stat; if ( ( (stat "$File::Find::name")[2] & 011) == 0 ) { push @dirs, $File::Find::name; } }
    Your "wanted" sub should push @result, $File::Find::name if ( /hello\.txt$/ ) where @result has higher scope than sub with File:Find. There is no way for File::Find to use the return value of "wanted". You have to use a higher scoped var for this "return function".

    Update: the above code looks for directories. It is more complex than what you need to do, but if you understand it, your code will be simple to do. Your code would return if -d (only look at files that are not directories). If you want to look at and find all files that match /hello\.txt$/i, you will have to look at every file in every sub-directory.

Re: 2 Questions on File::Find
by CountZero (Bishop) on Jul 18, 2009 at 19:28 UTC
    File::Find is such a strange beast. I always drop it in favour of File::Find::Rule.

    CountZero

    A program should be light and agile, its subroutines connected like a string of pearls. The spirit and intent of the program should be retained throughout. There should be neither too little or too much, neither needless loops nor useless variables, neither lack of structure nor overwhelming rigidity." - The Tao of Programming, 4.1 - Geoffrey James