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

Hi Monks, I want to traverse each file of a directory in descending order of modification time of the file using File::Find. So if there are two files 1. abc.C modified 8 days back. 2. xyz.C modifies 10 days back. xyz.C will be listed first. Is there a way to do this using File::Find ?
  • Comment on How do I traverse the files in descending order of modification using File::Find

Replies are listed 'Best First'.
Re: How do I traverse the files in descending order of modification using File::Find
by almut (Canon) on Apr 03, 2009 at 21:32 UTC

    You can have files be sorted on a per-directory basis using the 'preprocess' option, but you cannot sort the complete set of files across the entire directory tree you're traversing, such that File::Find would report the oldest file of all files first (at least I wouldn't know how). If you need that, you'd have to store everything into an intermediate array, and then sort that yourself.

    "preprocess"
    The value should be a code reference. This code reference is used to preprocess the current directory. The name of the currently processed directory is in $File::Find::dir. Your preprocessing function is called after "readdir()", but before the loop that calls the "wanted()" function. It is called with a list of strings (actually file/directory names) and is expected to return a list of strings. The code can be used to sort the file/directory names alphabetically, numerically, or to filter out directory entries based on their name alone. When follow or follow_fast are in effect, "preprocess" is a no-op.
Re: How do I traverse the files in descending order of modification using File::Find
by runrig (Abbot) on Apr 03, 2009 at 21:40 UTC
    You can traverse the entire directory structure, save the file name and modification times, and then sort the results. Would that be acceptable?
      I thought of it initialy but didnt want to modify the existing code which are is already usin File::Find. If I dont have any choice I will go for it , could you please let me know how I can go about doing that?
        Save the filenames/times in a hash:
        my %file_times; # Then in the wanted function: $file_times{$File::Find::name} = -M $_;
        Process the files in order of modification time (see sort and How do I sort a hash by value).

        If you want to avoid modifying existing code too much, you could try something like

        use File::Find; my @files; find(\&collect, "."); sub collect { # 'wanted' function replacement push @files, [ $File::Find::name, (stat)[9] # mtime ]; } sub wanted { # your original 'wanted' function # ... } my @files_by_age = sort { $a->[1] <=> $b->[1] } @files; for my $entry (@files_by_age) { my $fullname = $entry->[0]; my ($dir, $name) = $fullname =~ /(.*?)([^\/]*)$/; # set variables that File::Find would have set $File::Find::name = $fullname; $File::Find::dir = $dir; $_ = $name; # depending on whether you need it, you might want to # chdir() into the directory # ("left as an exercise ..." :) # call wanted() function as File::Find would have done wanted(); }

        (Depending on exactly how you're using File::Find, you might need to finetune the approach... this is just an outline of basic usage.)