Как я могу найти самый новый файл.pl в каталоге и во всех его подкаталогах, используя Perl?
Как я могу сканировать содержимое всего каталога, включая содержимое его подкаталогов, и найти самое новое .pl
файл внутри них с помощью Perl?
Я хочу построить отсортированный массив / список полных путей к файлам всех .pl
файлы в дереве каталогов.
Так, например, если мой базовый каталог /home/users/cheeseconqueso/
Я хочу искать .pl
файлы в этом каталоге и любом подкаталоге в этом пути, а затем сортировать .pl
файлы по дате.
Конечным результатом будет массив, @pl_paths
, где $pl_paths[0]
было бы что-то вроде /home/users/cheeseconqueso/maybe_not_newest_directory/surely_newest_file.pl
Исходя из этого, я хочу выполнить файл, но я думаю, как только я выясню, отсортированный массив, выполняя файл в $pl_paths[0]
не будет проблемой.
Есть аналогичный вопрос о SO, который я пытался изменить в соответствии со своими потребностями, но я здесь сейчас по очевидным причинам.
Код, который я использую для получения новейшего файла NAME только в одном каталоге:
opendir(my $DH, $DIR) or die "Error opening $DIR: $!";
my %files = map { $_ => (stat("$DIR/$_"))[9] } grep(! /^\.\.?$/, readdir($DH));
closedir($DH);
my @sorted_files = sort { $files{$b} <=> $files{$a} } (keys %files);
print $sorted_files[0]."\n";
3 ответа
Вы можете использовать File::Find, если вам нужен основной модуль для этого, но я бы предпочел использовать File::Find:: Rule.
Для начала мы можем найти все .pl
файлы в каталоге с
use File::Find::Rule;
my @files = File::Find::Rule->file
->name('*.pl')
->in($directory);
Тогда давайте использовать map
чтобы связать имена файлов со временем их изменения:
my @files_with_mtimes = map +{ name => $_, mtime => (stat $_)[9] }, @files;
И отсортировать их по mtime:
my @sorted_files = reverse sort { $a->{mtime} <=> $b->{mtime} }
@files_with_mtimes;
И оттуда, имя новейшего в $sorted_files[0]{name}
,
Если вы хотите найти только верхний вариант, на самом деле нет нужды делать полную сортировку, но самое хорошее решение, о котором я могу подумать, - это немного продвинутый FP, так что не беспокойтесь об этом, если он вам покажется странным:
use List::Util 'reduce';
my ($top_file) = reduce { $a->{mtime} >= $b->{mtime} ? $a : $b }
@files_with_mtimes;
С File::Find::Rule и преобразованием Шварца вы можете получить новейший файл с расширением.pl в поддереве, начиная с 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 ];
Цепочка map-sort-map является типичной идиомой: получение метки времени происходит медленно, поэтому мы делаем это только один раз для каждого файла, сохраняя каждую метку времени вместе с файлом в arrayref. Затем мы сортируем новый список с использованием метки времени (сравнивая второй элемент каждого массива) и, наконец, отбрасываем метки времени, сохраняя только имена файлов.