How can I scan an entire directory\'s contents, including its subdirectories\' contents, and find the newest .pl
file within them using Perl?
I want to
Use the File::Find core module.
You can use File::Find if you want a core module for this, but I would prefer to use File::Find::Rule.
To start off, we can find all of the .pl
files under a directory with
use File::Find::Rule;
my @files = File::Find::Rule->file
->name('*.pl')
->in($directory);
Then let's use map
to associate filenames with their modification times:
my @files_with_mtimes = map +{ name => $_, mtime => (stat $_)[9] }, @files;
And sort them by mtime:
my @sorted_files = reverse sort { $a->{mtime} <=> $b->{mtime} }
@files_with_mtimes;
And from there, the name of the newest one is in $sorted_files[0]{name}
.
If you only want to find the top one, there's actually no need to do a complete sort, but the nicest solution I can think of involves some slightly advanced FP, so don't worry about it at all if it looks strange to you:
use List::Util 'reduce';
my ($top_file) = reduce { $a->{mtime} >= $b->{mtime} ? $a : $b }
@files_with_mtimes;
With File::Find::Rule, and Schwartzian transform, you can get the newest file with .pl extension, in a subtree starting from dir_path.
#!/usr/bin/env perl
use v5.12;
use strict;
use File::Find::Rule;
my @files = File::Find::Rule->file()->name( '*.pl' )->in( 'dir_path' );
# Note that (stat $_ )[ 9 ] yields last modified timestamp
@files =
map { $_->[ 0 ] }
sort { $b->[ 1 ] <=> $a->[ 1 ] }
map { [ $_, ( stat $_ )[ 9 ] ] } @files;
# Here is the newest file in path dir_path
say $files[ 0 ];
The map-sort-map chain is a typical idiom: getting timestamp is slow, so we do it only one time per file, keeping every timestamp with its file in an arrayref. Then we sort the new list using timestamp ( comparing the second element of each arrayref ), and finally we discard timestamps, keeping only filenames.