2017-08-11 29 views
0

我的文件下面的列表: INV_1400524_20170412_052945.pdf INV_1400524_20170412_063522.pdf INV_1400524_20170412_090338.pdf INV_1400524_20170412_092911.pdf INV_1400971_20170502_095250.pdf INV_1401580_20170703_100410.pdf INV_1401880_20170804_112917.pdf RIN_1300355_20170503_014347.pdf RIN_1300552_20170518_111143.pdf RIN_1300552_20170518_122055.pdf RIN_1300688_20170627_040340.pdf RIN_1300834_20170727_113641.pdf RIN_1300834_20170727_154404.pdf 如何筛选下来的文件列表删除已知的重复

它的格式为:

<Document Type>_<Document Number>_<Date>_<Time>.pdf

正如你所看到的,对于一些原因相同的文件编号已被输出多次。我想忽略重复项并将列表过滤为唯一的文档号和最新的日期。这些文档还有一个修改过的文件时间戳,如果有帮助的话,它与文件名中的日期和时间紧密匹配。

使用perl(我一直在使用文件::查找::规则)我要下来减少列表: INV_1400524_20170412_092911.pdf INV_1400971_20170502_095250.pdf INV_1401580_20170703_100410.pdf INV_1401880_20170804_112917.pdf RIN_1300355_20170503_014347.pdf RIN_1300552_20170518_122055.pdf RIN_1300688_20170627_040340.pdf RIN_1300834_20170727_154404.pdf

我已经开始用

my @pdf_files = File::Find::Rule->new 
    ->in($root_dir) 
    ->name('*.pdf') 
    ->mtime (">$days_ago"); 

但是看着这个答案: How can I find the newest .pl file in a directory and all its subdirectories using Perl?

我认为有可能使用的方式:

my $rule = File::Find::Rule->new; 
$rule->or($rule->new->name('INV_*.pdf')->.... 
$rule->or($rule->new->name('RIN_*.pdf')->.... 
my @files = $rule->in($root_dir); 

将它们分组并过滤掉。有任何想法吗?

回答

1

有使用grep一个不错的成语:

my %seen; 
my @files = grep { not $seen{$_}++ } @files; 

因为你递增后,测试结果是真第一次,假所有的人。您也可以使用正则表达式在例如文档ID:

#!/usr/bin/env perl 

use strict; 
use warnings; 

use Data::Dumper; 

chomp(
    my @files = <DATA> 
); 

my %seen; 
@files = grep { m/(\d+)/ and not $seen{$1}++ } @files; 

print Dumper \@files; 

__DATA__ 
INV_1400524_20170412_052945.pdf 
INV_1400524_20170412_063522.pdf 
INV_1400524_20170412_090338.pdf 
INV_1400524_20170412_092911.pdf 
INV_1400971_20170502_095250.pdf 
INV_1401580_20170703_100410.pdf 
INV_1401880_20170804_112917.pdf 
RIN_1300355_20170503_014347.pdf 
RIN_1300552_20170518_111143.pdf 
RIN_1300552_20170518_122055.pdf 
RIN_1300688_20170627_040340.pdf 
RIN_1300834_20170727_113641.pdf 
RIN_1300834_20170727_154404.pdf 

此输出:

$VAR1 = [ 
      'INV_1400524_20170412_052945.pdf', 
      'INV_1400971_20170502_095250.pdf', 
      'INV_1401580_20170703_100410.pdf', 
      'INV_1401880_20170804_112917.pdf', 
      'RIN_1300355_20170503_014347.pdf', 
      'RIN_1300552_20170518_111143.pdf', 
      'RIN_1300688_20170627_040340.pdf', 
      'RIN_1300834_20170727_113641.pdf' 
     ]; 

如果您的条件更compliated,那么你可能需要申请一个排序,以确保“第一”被过滤到顶部。

有两种方式存在 - 或者你可以sort在文件名上 - 因为你有一个ISO日期,这看起来会工作:

@files = grep { m/(\d+)/ and not $seen{$1}++ } sort @files; 

或者你也可以以此为基础进行制​​作某种stat系统调用(这个你需要完整的文件路径,虽然,因此被警告!)

@files = grep { m/(\d+)/ and not $seen{$1}++} sort { -M $a <=> -M $b } @files; 

-M是Perl filetest,检查文件的时间(以天)。

但是,您可以使用stat

+0

谢谢 - 会试试看。正如您在上面指出的那样,我正在寻找最近的日期,而不是最早的日期。 – mccannf

+0

您可能需要在排序标准中交换'$ a'和'$ b'。但就是这些。 – Sobrique

+1

它实际上使用'@files = grep {m /(\ d +)/而不是$见过{$ 1} ++}反向排序@files;' – mccannf