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

yvf*_*ya4 3 arrays perl duplicates

我一直在尝试编写一个脚本来预处理一些长文件列表,但我对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";
        }
    } 
}
Run Code Online (Sandbox Code Playgroud)

我正在努力理解我的重复检查有什么问题.我知道数组包含重复项(取消注释第一个打印函数给我一个包含大量重复项的列表).它所代表的代码不会产生任何结果.

这不是我的帖子的主要目的,但我的最终目的是从列表中删除唯一的文件名,并保留在其他目录中重复的文件名.我知道这些文件都不相同,但很多是同一文件的不同版本,这就是为什么我专注于文件名.

我想要输入:

〜/ Pictures/2010/12345678.jpg~/Pictures/2010/12341234.jpg~/Desktop/temp/12345678.jpg

给出一个输出:

〜/ Pictures/2010/12345678.jpg~/Desktop/temp/12345678.jpg

所以我认为理想情况下,如果可能的话,最好根据正则表达式检查匹配的唯一性而不分裂.

TLP*_*TLP 5

以下循环不执行任何操作,因为散列和数组仅包含每个循环迭代的一个值:

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
Run Code Online (Sandbox Code Playgroud)

词法变量(声明为my)的范围扩展到周围的块{ ... },在本例中是foreach循环.当它们超出范围时,它们将被重置并且所有数据都将丢失.

我不知道为什么你复制的文件名@split@filenames,似乎很是多余的.重复数据删除的方法是:

my %seen;
my @uniq;

@uniq = grep !$seen{$_}++, @split;
Run Code Online (Sandbox Code Playgroud)

附加信息:

您可能还有兴趣使用File::Basename获取文件名:

use File::Basename;
my $fullpath = "~/Pictures/2010/12345678.jpg";
my $name = basename($fullpath);                  # 12345678.jpg
Run Code Online (Sandbox Code Playgroud)

你的替代

$line =~ s/\n//;
Run Code Online (Sandbox Code Playgroud)

应该是

chomp($line);
Run Code Online (Sandbox Code Playgroud)

当您从文件句柄中读取时,使用for(foreach)表示您读取所有行并将它们存储在内存中.大多数情况下,最好使用while,如下所示:

while (my $line = <$fh>)
Run Code Online (Sandbox Code Playgroud)