Tìm kiếm tên tập tin trùng lặp trong phân cấp thư mục?


29

Tôi có một thư mục được gọi img, thư mục này có nhiều cấp thư mục con, tất cả đều chứa hình ảnh. Tôi sẽ nhập chúng vào một máy chủ hình ảnh.

Thông thường hình ảnh (hoặc bất kỳ tệp nào) có thể có cùng tên miễn là chúng nằm trong một đường dẫn thư mục khác hoặc có phần mở rộng khác nhau. Tuy nhiên, máy chủ hình ảnh tôi đang nhập chúng vào yêu cầu tất cả các tên hình ảnh là duy nhất (ngay cả khi các tiện ích mở rộng khác nhau).

Ví dụ: hình ảnh background.pngbackground.gifsẽ không được phép vì mặc dù chúng có các phần mở rộng khác nhau nhưng chúng vẫn có cùng tên tệp. Ngay cả khi chúng nằm trong các thư mục con riêng biệt, chúng vẫn cần phải là duy nhất.

Vì vậy, tôi tự hỏi nếu tôi có thể thực hiện tìm kiếm đệ quy trong imgthư mục để tìm danh sách các tệp có cùng tên (không bao gồm phần mở rộng).

Có một lệnh có thể làm điều này?


@DavidFoerster Bạn nói đúng! Tôi không biết tại sao tôi lại nghĩ đây có thể là một bản sao của Cách tìm (và xóa) các tệp trùng lặp , nhưng rõ ràng là không phải vậy.
Eliah Kagan

Câu trả lời:


17

FSlint Cài đặt fslint là một công cụ tìm trùng lặp linh hoạt bao gồm chức năng tìm tên trùng lặp:

FSlint

Gói FSlint cho Ubuntu nhấn mạnh vào giao diện đồ họa, nhưng như được giải thích trong Câu hỏi thường gặp của FSlint , giao diện dòng lệnh có sẵn thông qua các chương trình trong /usr/share/fslint/fslint/. Sử dụng --helptùy chọn cho tài liệu, ví dụ:

$ /usr/share/fslint/fslint/fslint --help
File system lint.
A collection of utilities to find lint on a filesystem.
To get more info on each utility run 'util --help'.

findup -- find DUPlicate files
findnl -- find Name Lint (problems with filenames)
findu8 -- find filenames with invalid utf8 encoding
findbl -- find Bad Links (various problems with symlinks)
findsn -- find Same Name (problems with clashing names)
finded -- find Empty Directories
findid -- find files with dead user IDs
findns -- find Non Stripped executables
findrs -- find Redundant Whitespace in files
findtf -- find Temporary Files
findul -- find possibly Unused Libraries
zipdir -- Reclaim wasted space in ext2 directory entries
$ /usr/share/fslint/fslint/findsn --help
find (files) with duplicate or conflicting names.
Usage: findsn [-A -c -C] [[-r] [-f] paths(s) ...]

If no arguments are supplied the $PATH is searched for any redundant
or conflicting files.

-A reports all aliases (soft and hard links) to files.
If no path(s) specified then the $PATH is searched.

If only path(s) specified then they are checked for duplicate named
files. You can qualify this with -C to ignore case in this search.
Qualifying with -c is more restictive as only files (or directories)
in the same directory whose names differ only in case are reported.
I.E. -c will flag files & directories that will conflict if transfered
to a case insensitive file system. Note if -c or -C specified and
no path(s) specifed the current directory is assumed.

Ví dụ sử dụng:

$ /usr/share/fslint/fslint/findsn /usr/share/icons/ > icons-with-duplicate-names.txt
$ head icons-with-duplicate-names.txt 
-rw-r--r-- 1 root root    683 2011-04-15 10:31 Humanity-Dark/AUTHORS
-rw-r--r-- 1 root root    683 2011-04-15 10:31 Humanity/AUTHORS
-rw-r--r-- 1 root root  17992 2011-04-15 10:31 Humanity-Dark/COPYING
-rw-r--r-- 1 root root  17992 2011-04-15 10:31 Humanity/COPYING
-rw-r--r-- 1 root root   4776 2011-03-29 08:57 Faenza/apps/16/DC++.xpm
-rw-r--r-- 1 root root   3816 2011-03-29 08:57 Faenza/apps/22/DC++.xpm
-rw-r--r-- 1 root root   4008 2011-03-29 08:57 Faenza/apps/24/DC++.xpm
-rw-r--r-- 1 root root   4456 2011-03-29 08:57 Faenza/apps/32/DC++.xpm
-rw-r--r-- 1 root root   7336 2011-03-29 08:57 Faenza/apps/48/DC++.xpm
-rw-r--r-- 1 root root    918 2011-03-29 09:03 Faenza/apps/16/Thunar.png

Cảm ơn điều này đã làm việc. Một số kết quả có màu tím và một số màu xanh lá cây. Bạn có biết những màu sắc khác nhau có nghĩa là gì?
JD Isaacks

@ John Có vẻ như FSlint đang sử dụng ls -lđể định dạng đầu ra của nó. Câu hỏi này sẽ giải thích ý nghĩa của màu sắc.
ændrük

FSlint có rất nhiều phụ thuộc.
Navin

31
find . -mindepth 1 -printf '%h %f\n' | sort -t ' ' -k 2,2 | uniq -f 1 --all-repeated=separate | tr ' ' '/'

Như các bình luận, điều này cũng sẽ tìm thấy các thư mục. Đây là lệnh để hạn chế nó vào các tập tin:

find . -mindepth 1 -type f -printf '%p %f\n' | sort -t ' ' -k 2,2 | uniq -f 1 --all-repeated=separate | cut -d' ' -f1

Tôi đã thay đổi giải pháp để nó trả về đường dẫn (tương đối) đầy đủ của tất cả các bản sao. Thật không may, nó giả định rằng tên đường dẫn không chứa khoảng trắng vì uniqkhông cung cấp tính năng để chọn một dấu phân cách trường khác.
David Foerster

@DavidFoerster, rev 6 của bạn là một sự cải tiến, nhưng liên quan đến nhận xét của bạn ở đó, kể từ khi nào là sedlỗi thời? Arcane? Chắc chắn rồi. Lỗi thời? Không phải là tôi biết. (Và tôi vừa tìm kiếm để kiểm tra.)
cp.engr

@ cp.engr: sed không lỗi thời. Lời cầu khẩn đã trở nên lỗi thời sau một thay đổi khác của tôi.
David Foerster

@DavidFoerster, lỗi thời dường như không phải là từ đúng với tôi. Tôi nghĩ rằng "bị che khuất" sẽ phù hợp hơn. Bất kể, cảm ơn đã làm rõ.
cp.engr

@ cp.engr: Cảm ơn lời đề nghị! Tôi không biết từ đó nhưng nó có vẻ phù hợp với hoàn cảnh hơn.
David Foerster

8

Lưu cái này vào một tập tin có tên duplicates.py

#!/usr/bin/env python

# Syntax: duplicates.py DIRECTORY

import os, sys

top = sys.argv[1]
d = {}

for root, dirs, files in os.walk(top, topdown=False):
    for name in files:
        fn = os.path.join(root, name)
        basename, extension = os.path.splitext(name)

        basename = basename.lower() # ignore case

        if basename in d:
            print(d[basename])
            print(fn)
        else:
            d[basename] = fn

Sau đó làm cho tập tin thực thi:

chmod +x duplicates.py

Chạy trong ví dụ như thế này:

./duplicates.py ~/images

Nó sẽ xuất ra các cặp tệp có cùng tên cơ sở (1). Viết bằng python, bạn sẽ có thể sửa đổi nó.


Nó dường như không hoạt động đúng. Nó phát hiện P001.ORFP001 (1).ORFlà bản sao và dường như cũng nghĩ rằng 60% tệp của tôi là bản sao sai, tôi khá chắc chắn. fslinttìm thấy một số tên thật trùng lặp gần 3%.
Rolf

3

Tôi giả sử bạn chỉ cần xem các "bản sao" này, sau đó xử lý chúng theo cách thủ công. Nếu vậy, mã bash4 này sẽ làm những gì bạn muốn tôi nghĩ.

declare -A array=() dupes=()
while IFS= read -r -d '' file; do 
    base=${file##*/} base=${base%.*}
    if [[ ${array[$base]} ]]; then 
        dupes[$base]+=" $file"
    else
        array[$base]=$file
    fi
done < <(find /the/dir -type f -print0)

for key in "${!dupes[@]}"; do 
    echo "$key: ${array[$key]}${dupes[$key]}"
done

Xem http://mywiki.wooledge.org/BashGuide/Arrays#Associative_Arrays và / hoặc hướng dẫn bash để được trợ giúp về cú pháp mảng kết hợp.


Làm thế nào để tôi thực hiện một lệnh như thế trong một thiết bị đầu cuối? Đây có phải là thứ tôi cần lưu vào một tệp trước và thực hiện tệp không?
JD Isaacks

@John Isaacks Bạn có thể sao chép / dán nó vào thiết bị đầu cuối hoặc bạn có thể đặt nó vào một tệp và chạy nó dưới dạng tập lệnh. Cả hai trường hợp sẽ đạt được như nhau.
geirha

1

Đây là tên hiệu:

#!/bin/bash
#
#  find for jpg/png/gif more files of same basename 
#
# echo "processing ($1) $2"
bname=$(basename "$1" .$2)
find -name "$bname.jpg" -or -name "$bname.png"

Làm cho nó thực thi:

chmod a+x bname 

Gọi nó:

for ext in jpg png jpeg gif tiff; do find -name "*.$ext" -exec ./bname "{}" $ext ";"  ; done

Chuyên nghiệp:

  • Nó đơn giản và đơn giản, do đó có thể mở rộng.
  • Xử lý khoảng trống, tab, ngắt dòng và nguồn cấp dữ liệu trong tên tệp, afaik. (Giả sử không có điều đó trong tên mở rộng).

Con:

  • Nó luôn tìm thấy tệp và nếu nó tìm thấy a.gif cho a.jpg, nó cũng sẽ tìm thấy a.jpg cho a.gif. Vì vậy, đối với 10 tệp có cùng tên cơ sở, cuối cùng nó sẽ tìm thấy 100 kết quả khớp.

0

Cải thiện tập lệnh của loevborg, cho nhu cầu của tôi (bao gồm đầu ra được nhóm, danh sách đen, đầu ra sạch hơn trong khi quét). Tôi đã quét một ổ đĩa 10TB, vì vậy tôi cần đầu ra sạch hơn một chút.

Sử dụng:

python duplicates.py DIRNAME

duplicates.py

    #!/usr/bin/env python

    # Syntax: duplicates.py DIRECTORY

    import os
    import sys

    top = sys.argv[1]
    d = {}

    file_count = 0

    BLACKLIST = [".DS_Store", ]

    for root, dirs, files in os.walk(top, topdown=False):
        for name in files:
            file_count += 1
            fn = os.path.join(root, name)
            basename, extension = os.path.splitext(name)

            # Enable this if you want to ignore case.
            # basename = basename.lower()

            if basename not in BLACKLIST:
                sys.stdout.write(
                    "Scanning... %s files scanned.  Currently looking at ...%s/\r" %
                    (file_count, root[-50:])
                )

                if basename in d:
                    d[basename].append(fn)
                else:
                    d[basename] = [fn, ]

    print("\nDone scanning. Here are the duplicates found: ")

    for k, v in d.items():
        if len(v) > 1:
            print("%s (%s):" % (k, len(v)))
            for f in v:
                print (f)
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.