Tìm tập tin có cùng tên nhưng nội dung khác nhau?


9

Tôi muốn tạo một danh sách các tệp có:

  • Cùng tên
  • Nội dung khác nhau

trong một thư mục (bao gồm tất cả các thư mục con và nội dung).

Làm thế nào để làm gì? Bash, perl, bất cứ điều gì là tốt.

Vì vậy, hai tệp có cùng tên và cùng một nội dung sẽ không hiển thị.


Giả sử có ba tệp có cùng tên và hai trong số ba tệp giống hệt nhau?
Kyle Jones

@KyleJones: "ba tệp có cùng tên và hai trong số ba tệp giống hệt nhau"> Sau đó, tên tệp này sẽ được thêm vào danh sách
Nicolas Raoul

Câu trả lời:


8

Cập nhật: đã sửa lỗi chính tả trong tập lệnh: đã đổi print $NFthành print $3; cũng dọn dẹp mọi thứ, và thêm một số ý kiến.

Giả sử tên tệp không chứa \n, phần sau sẽ in ra một danh sách được sắp xếp ngắt (như trong: ngắt điều khiển phần ) ở mức duy nhất file name, duy nhất md5sumvà hiển thị nhóm đường dẫn tệp tương ứng.

#!/bin/bash

# Choose which script to use for the final awk step 
out_script=out_all

# Print all duplicated file names, even when md5sum is the same 
out_all='{ if( p1 != $1 ) { print nl $1; print I $2 }
      else if( p2 != $2 ) { print I $2 }
      print I I $3; p1=$1; p2=$2; nl="\n" }
   END { printf nl}'

# Print only duplicated file names which have multiple md5sums.
out_only='{ if( p1 != $1 ) { if( multi ) { print pend }
                             multi=0; pend=$1 "\n" I $2 "\n" }
       else if( p2 != $2 ) { multi++; pend=pend I $2 "\n" } 
       pend=pend I I $3 "\n"; p1=$1; p2=$2 } 
   END { if( multi ) print pend }'

# The main pipeline 
find "${1:-.}" -type f -name '*' |  # awk for duplicate names
awk -F/ '{ if( name[$NF] ) { dname[$NF]++ }
           name[$NF]=name[$NF] $0 "\n" } 
     END { for( d in dname ) { printf name[d] } 
   }' |                             # standard md5sum output 
xargs -d'\n' md5sum |               # " "==text, "*"==binary
sed 's/ [ *]/\x00/' |               # prefix with file name  
awk -F/ '{ print $3 "\x00" $0 }' |  # sort by name. md5sum, path 
sort |                              # awk to print result
awk -F"\x00" -v"I=   " "${!out_script}"

Đầu ra chỉ hiển thị tên tệp có nhiều md5 s

afile.html
   53232474d80cf50b606069a821374a0a
      ./test/afile.html
      ./test/dir.svn/afile.html
   6b1b4b5b7aa12cdbcc72a16215990417
      ./test/dir.svn/dir.show/afile.html

Đầu ra hiển thị tất cả các tệp có cùng tên.

afile.html
   53232474d80cf50b606069a821374a0a
      ./test/afile.html
      ./test/dir.svn/afile.html
   6b1b4b5b7aa12cdbcc72a16215990417
      ./test/dir.svn/dir.show/afile.html

fi    le.html
   53232474d80cf50b606069a821374a0a
      ./test/dir.svn/dir.show/fi    le.html
      ./test/dir.svn/dir.svn/fi    le.html

file.html
   53232474d80cf50b606069a821374a0a
      ./test/dir.show/dir.show/file.html
      ./test/dir.show/dir.svn/file.html

file.svn
   53232474d80cf50b606069a821374a0a
      ./test/dir.show/dir.show/file.svn
      ./test/dir.show/dir.svn/file.svn
      ./test/dir.svn/dir.show/file.svn
      ./test/dir.svn/dir.svn/file.svn

file.txt
   53232474d80cf50b606069a821374a0a
      ./test/dir.show/dir.show/file.txt
      ./test/dir.show/dir.svn/file.txt
      ./test/dir.svn/dir.show/file.txt
      ./test/dir.svn/dir.svn/file.txt

1

Đây là một kịch bản Perl. Chạy nó trong thư mục ở đầu cây bạn muốn tìm kiếm. Kịch bản phụ thuộc vào findmd5, nhưng sau này có thể được thay thế bằng sha1, sumhoặc bất kỳ chương trình băm tập tin khác mà chấp nhận đầu vào trên stdin và kết quả đầu ra một hash trên stdout.

use strict;

my %files;
my %nfiles;
my $HASHER = 'md5';

sub
print_array
{
    for my $x (@_) {
        print "$x\n";
    }
}

open FINDOUTPUT, "find . -type f -print|" or die "find";

while (defined (my $line = <FINDOUTPUT>)) {
    chomp $line;
    my @segments = split /\//, $line;
    my $shortname = pop @segments;
    push @{ $files{$shortname} }, $line;
    $nfiles{$shortname}++;
}

for my $shortname (keys %files) {
    if ($nfiles{$shortname} < 2) {
        print_array @{ $files{$shortname} };
        next;
    }
    my %nhashes;
    my %revhashes;
    for my $file (@{ $files{$shortname} }) {
        my $hash = `$HASHER < $file`;
        $revhashes{$hash} = $file;
        $nhashes{$hash}++;
    }
    for my $hash (keys %nhashes) {
        if ($nhashes{$hash} < 2) {
            my $file = $revhashes{$hash};
            print "$file\n";
        }
    }
}


1

Đối với những người muốn nhìn thấy chỉ là một danh sách các tên tập tin, đây là phần có liên quan của Peter.O 's câu trả lời :

find "${1:-.}" -type f -name '*' | 
awk -F/ '{ if( name[$NF] ) { dname[$NF]++ }
       name[$NF]=name[$NF] $0 "\n" } 
 END { for( d in dname ) { printf name[d] "\n" } 

} '

Tôi không cần md5sums vì tôi sử dụng fslint-guitrước tập lệnh để xóa tất cả các bản sao.


trên máy mac của tôi, phần này hiển thị các tệp trùng lặp cùng tên cùng nội dung
nightograph
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.