【问题标题】:Deleting smaller sized dupes of files删除较小尺寸的重复文件
【发布时间】:2009-10-30 01:26:10
【问题描述】:

我正在尝试查找具有相同名称的文件并删除所有较小的副本,只留下最大的副本。例如:test.jpg=2kb,test.jpg=9kb,test.jpg=5kb。 2kb 和 5kb 文件将被删除,只留下 9kb。我已经尝试了几个 GUI 程序来执行此操作,但它们没有任何帮助,因为您必须在找到副本后手动删除所有内容(当有大约 400000 个重复项时,这不是很好!)是否有脚本可以这样做有人知道吗?

【问题讨论】:

    标签: shell filenames delete-file


    【解决方案1】:

    这会查找所有文件并打印它们的名称、大小和名称与路径。然后它按名称对它们进行排序,然后按大小(降序)然后按路径排序。 awk 脚本通过除第一个(最大)之外的所有脚本,xargs 将它们交给echo(删除echo 以使rm 采取行动)。这应该适用于名称中包含空格的文件,但不适用于名称中包含换行符或制表符的文件。

    find -type f -printf "%f\t%s\t%p\n" |
        sort -t $'\t' -k 1,1 -k 2,2rn -k 3,3 |
        awk -F'\t' '{if ( $1 == prevfile) printf "%s\0", $3; prevfile = $1}' |
        xargs -0 -I{} echo rm \{\}
    

    在这个目录结构中(由tree -s 生成),所有名为“file”的文件都将被删除,除了test/dir/dir/file 最大的50 字节。

    test
    |-- [    26]  file
    |-- [  4096]  dir
    |   |-- [    34]  file
    `-- [  4096]  dir
        |-- [  4096]  dir
        |   |-- [    50]  file
        `-- [  4096]  test
            `-- [  4096]  dir
                `-- [    20]  file
    

    【讨论】:

    • 我们确实需要添加 --head/--tail 或等效的排序。这将在功能和算法上都有益
    • 是的,我想我同意。它已经有 -u 的唯一性,所以它看起来很合适。
    【解决方案2】:

    这个 perl 脚本查找从当前目录开始的所有文件。然后将它们放入一个散列中,其中文件的基本名称是键,值是 (size, fullpath) 对。然后它遍历基本名称,对重复项进行排序并删除除最大的以外的所有名称。

    实际的 /bin/rm 被注释掉了。在真正做之前,请确保它符合您的要求。

    真正的 perl 黑客:如果我在这里做一些幼稚/愚蠢的事情,我很想了解。

    #!/usr/bin/perl -w
    use File::Basename;
    use strict;
    
    my @files = `/usr/bin/find -type f`;
    my %stats;
    
    # each hash key is the simple basename of the files
    # each hash value is a 2 element array of (size, fullpath)
    foreach my $file (@files)
    {
        chomp($file);
        my $result = `/bin/ls -s $file`;
        chomp($result);
        if($result =~ /^(\d+)\s+(.*)/)
        {   
            my ($basefile, $dir, $suffix) = fileparse($file);
            push(@{$stats{$basefile}}, [$1, $2]);
        }
        else
        {   
            printf STDERR "Unexpected ls output: $result\n";
        }
    }
    
    foreach my $file (keys %stats)
    {
        # sort from smallest to largest
        my @sorted = sort {$b->[0] <=> $a->[0]} @{$stats{$file}};
    
        # remove the biggest one
        pop(@sorted);
    
        # for each one that's left remove it (use at your own risk!)
        foreach my $path (@sorted)
        {   
            # system("/bin/rm $path");
            printf "/bin/rm $path->[1]\n";
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-04-13
      • 1970-01-01
      • 2017-02-23
      • 2013-04-30
      • 1970-01-01
      • 2018-03-20
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多