Как я могу найти самый новый файл .pl в каталоге и во всех его подкаталогах, используя Perl? - PullRequest
4 голосов
/ 28 сентября 2011

Как я могу сканировать содержимое всего каталога, включая содержимое его подкаталогов, и найти в них самый новый файл .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 ]

13 голосов
/ 28 сентября 2011

Вы можете использовать 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;
4 голосов
/ 28 сентября 2011

Используя 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. Затем мы сортируем новый список, используя метку времени (сравнивая второй элемент каждого arrayref), и, наконец, отбрасываем метки времени, сохраняя только имена файлов.

2 голосов
/ 28 сентября 2011

Используйте основной модуль File :: Find .

...