perllast-modified

How can I find the newest created file in a directory?


Is there an elegant way in Perl to find the newest file in a directory (newest by modification date)?

What I have so far is searching for the files I need, and for each one get it's modification time, push into an array containing the filename, modification time, then sort it.

There must be a better way.


Solution

  • Your way is the "right" way if you need a sorted list (and not just the first, see Brian's answer for that). If you don't fancy writing that code yourself, use this

    use File::DirList;
    my @list = File::DirList::list('.', 'M');
    

    Personally I wouldn't go with the ls -t method - that involves forking another program and it's not portable. Hardly what I'd call "elegant"!


    Regarding rjray's solution hand coded solution, I'd change it slightly:

    opendir(my $DH, $DIR) or die "Error opening $DIR: $!";
    my @files = map { [ stat "$DIR/$_", $_ ] } grep(! /^\.\.?$/, readdir($DH));
    closedir($DH);
    
    sub rev_by_date { $b->[9] <=> $a->[9] }
    my @sorted_files = sort rev_by_date @files;
    

    After this, @sorted_files contains the sorted list, where the 0th element is the newest file, and each element itself contains a reference to the results of stat, with the filename itself in the last element:

    my @newest = @{$sorted_files[0]};
    my $name = pop(@newest);
    

    The advantage of this is that it's easier to change the sorting method later, if desired.


    EDIT: here's an easier-to-read (but longer) version of the directory scan, which also ensures that only plain files are added to the listing:

    my @files;
    opendir(my $DH, $DIR) or die "Error opening $DIR: $!";
    while (defined (my $file = readdir($DH))) {
      my $path = $DIR . '/' . $file;
      next unless (-f $path);           # ignore non-files - automatically does . and ..
      push(@files, [ stat(_), $path ]); # re-uses the stat results from '-f'
    }
    closedir($DH);
    

    NB: the test for defined() on the result of readdir() is because a file called '0' would cause the loop to fail if you only test for if (my $file = readdir($DH))