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

Dearest Monks,

I would like to search through all the files in a directory, and see if at least one of them is new (m-time, say). When I find one, i need to stop the depth-search.

Your thoughts will be highly appreciated!

use strict; use warnings; use File::Find; my $base = '/my/working/directory'; finddepth(\&no_old_dir_please, $base); sub no_old_dir_please { return if ((-M $_) <= 30); # how to quit finddepth on this con +dition? }

I know I could set a flag once i hit a new file and then just return in the sub if that flag is true. But the reason i want to stop processing is that there could 100 /1000 more files but the moment I find a new file there is no point in checking other files.

To summarize in the problem in a line: Flag the given directory as "old" if there are no new files (based on some m-time condn).

Thanks!

-SK

Update: I don't want to quit the program as I could be checking a bunch of directories like this in a loop.

Replies are listed 'Best First'.
Re: How to conditionally terminate finddepth?
by graff (Chancellor) on Sep 12, 2005 at 22:15 UTC
    Perhaps others will see a "better" way, but having scanned the man page for File::Find, the only thing I could think of would be to issue a "die" in the "wanted" sub, and wrap the "finddepth()" call in an eval:
    eval "finddepth(\\&wanted,\$base)"; if ( $@ ) { print "new file: $@\n"; } sub wanted { die $File::Find::name if ( -M _ <= 30 ); }
    (updated to include the underscore in "wanted")
      Good answer, but there's no reason to do a string eval. Get some efficiency and compile time checking (and save some backslashes) with a block eval:
      eval { finddepth(\&wanted, $base) };
      Nice, but I'd be wary of missing some other important die in there, (say, a directory read error, or something equally dire) so would do:
      my $newfile = undef; eval { finddepth( sub {if (-M $_ <= 30) {$newfile=$File::Find::name; die "";}}, $base); }; die "$@" if ($@ and !defined($newfile)); if (defined($newfile)) {print "$base has something new in it\n";} else {print "$base is just old stuff\n";}
      --
      @/=map{[/./g]}qw/.h_nJ Xapou cets krht ele_ r_ra/; map{y/X_/\n /;print}map{pop@$_}@/for@/
        Or you could forgo eval/die and use goto
        my $newfile = undef; finddepth( sub { if (-M $_ <= 30){ $newfile=$File::Find::name; goto done_finddepth; } }, $base ); done_finddepth: die "the new file is $newfile";
        I once suggested an official breakout function to the perl5-porter, to be used like
        my $count = 0; &find( sub { $count++; File::Find::breakout() if $count == 500; }, '/');
        but nothing came of it. File::Find's way of doing things can mess with your head.

        MJD says "you can't just make shit up and expect the computer to know what you mean, retardo!"
        I run a Win32 PPM repository for perl 5.6.x and 5.8.x -- I take requests (README).
        ** The third rule of perl club is a statement of fact: pod is sexy.

      Thanks very much graff. That did it! Very good use of the eval-die combo!

      print "$base: old directory\n" if (not $@);
      :-)

      -SK

Re: How to conditionally terminate finddepth?
by GrandFather (Saint) on Sep 12, 2005 at 22:08 UTC

    Use a global flag to say you are done:

    use strict; use warnings; use File::Find; my $base = '/my/working/directory'; my $done = 0; finddepth(\&no_old_dir_please, $base); sub no_old_dir_please { $done ||= (-M $_) <= 30; $File::Find::prune = $done; }

    Update: Read the docs before replying next time :)

    Note, not tested


    Perl is Huffman encoded by design.