Arrays 使用Perl创建重复文件名列表

Arrays 使用Perl创建重复文件名列表,arrays,perl,duplicates,Arrays,Perl,Duplicates,我一直在尝试编写一个脚本来预处理一些长的文件列表,但我对Perl没有信心(也没有能力),也没有得到我想要的结果 下面的脚本正在进行中,但我仍在检查副本,如果有人能告诉我哪里出了问题,我将不胜感激。处理重复项的块似乎与我发现的示例的形式相同,但似乎不起作用 #!/usr/bin/perl use strict; use warnings; open my $fh, '<', $ARGV[0] or die "can't open: $!"; foreach my $line (<$

我一直在尝试编写一个脚本来预处理一些长的文件列表,但我对Perl没有信心(也没有能力),也没有得到我想要的结果

下面的脚本正在进行中,但我仍在检查副本,如果有人能告诉我哪里出了问题,我将不胜感激。处理重复项的块似乎与我发现的示例的形式相同,但似乎不起作用

#!/usr/bin/perl
use strict;
use warnings;

open my $fh, '<', $ARGV[0] or die "can't open: $!";

foreach my $line (<$fh>) {

#   Trim list to remove directories which do not need to be checked
    next if $line =~ m/Inventory/;
#   MORE TO DO 
    next if $line =~ m/Scanned photos/;

    $line =~ s/\n//; # just for a tidy list when testing
    my @split = split(/\/([^\/]+)$/, $line); # separate filename from rest of path

    foreach (@split) {
        push (my @filenames, "$_");
#       print "@filenames\n"; # check content of array

        my %dupes;

        foreach my $item (@filenames) {
            next unless $dupes{$item}++;
            print "$item\n";
        }
    } 
}
#/usr/bin/perl
严格使用;
使用警告;

打开我的$fh,“下面的循环没有任何作用,因为哈希和数组对于每个循环迭代只包含一个值:

foreach (@split) {
    push (my @filenames, "$_");        # add one element to lexical array
    my %dupes;
    foreach my $item (@filenames) {    # loop one time
        next unless $dupes{$item}++;   # add one key to lexical hash
        print "$item\n";
    }
}                                      # @filenames and %dupes goes out of scope
词法变量(用
my
声明)的作用域扩展到周围的块
{…}
,在本例中是
foreach
循环。当它们超出范围时,会被重置,所有数据都会丢失

我不知道你为什么要把文件名从
@split
复制到
@filenames
,这看起来很多余。消除重复数据的方法是:

my %seen;
my @uniq;

@uniq = grep !$seen{$_}++, @split;

其他信息:

您可能还对使用获取文件名感兴趣:

use File::Basename;
my $fullpath = "~/Pictures/2010/12345678.jpg";
my $name = basename($fullpath);                  # 12345678.jpg
你的替代品

$line =~ s/\n//;
应该是

chomp($line);
当您从文件句柄读取时,使用
for
foreach
)意味着您读取所有行并将它们存储在内存中。大多数情况下,最好在
时使用
,如下所示:

while (my $line = <$fh>)
while(我的$line=)

TLP的回答提供了很多好的建议。此外:

为什么同时使用数组和哈希来存储文件名?只需使用散列作为一个存储解决方案,就可以自动删除重复项。i、 e:

my %filenames; #outside of the loops

...

foreach (@split) {
    $filenames{$_}++;
}

现在,当您想要获得唯一文件名列表时,只需使用
键%filenames
,或者,如果您想要按字母顺序排列,则使用
排序键%filenames
。每个散列键的值都是出现次数的计数,因此如果您愿意,您可以找出哪些是重复的。

谢谢TLP。这些都非常有用。我显然需要更加注意范围。grep的使用当然对我有用,尽管我删除了“!”,因为我想删除唯一的项,而不删除重复项。basename函数特别有用。我以前没有遇到过它,但它让我大大简化了我的工作。谢谢@dan1111,但我使用数组的原因是我想保留重复项而不是删除它们,在使用split之后,我在文件名和路径上得到了重复项。不过,使用TLP建议的basename让我摆脱了数组。