ค้นหาชื่อไฟล์ที่ซ้ำกันภายในลำดับชั้นของโฟลเดอร์?


29

ฉันมีโฟลเดอร์ชื่อโฟลเดอร์imgนี้มีโฟลเดอร์ย่อยหลายระดับซึ่งทั้งหมดมีรูปภาพ ฉันกำลังจะนำเข้ามันไปยังเซิร์ฟเวอร์อิมเมจ

โดยทั่วไปรูปภาพ (หรือไฟล์ใด ๆ ) อาจมีชื่อเหมือนกันตราบใดที่อยู่ในพา ธ ไดเร็กทอรีอื่นหรือมีนามสกุลต่างกัน อย่างไรก็ตามเซิร์ฟเวอร์อิมเมจที่ฉันกำลังนำเข้าต้องมีชื่อรูปภาพทั้งหมดไม่ซ้ำกัน (แม้ว่าส่วนขยายจะแตกต่างกัน)

ตัวอย่างเช่นรูปภาพbackground.pngและbackground.gifจะไม่ได้รับอนุญาตเพราะแม้ว่าจะมีนามสกุลต่างกัน แต่ก็ยังมีชื่อไฟล์เหมือนกัน แม้ว่าพวกเขาจะอยู่ในโฟลเดอร์ย่อยที่แยกจากกันพวกเขายังคงต้องไม่ซ้ำกัน

ดังนั้นฉันสงสัยว่าฉันสามารถทำการค้นหาซ้ำในimgโฟลเดอร์เพื่อค้นหารายการไฟล์ที่มีชื่อเดียวกัน (ไม่รวมส่วนขยาย)

มีคำสั่งที่สามารถทำได้หรือไม่?


@DavidFoerster คุณพูดถูก! ฉันไม่รู้ว่าทำไมฉันจึงคิดว่านี่อาจเป็นไฟล์ที่ซ้ำกันของHow to find (and delete)แต่มันไม่ชัดเจน
Eliah Kagan

คำตอบ:


17

FSlint ติดตั้ง fslintเป็นตัวค้นหาซ้ำซ้อนอเนกประสงค์ที่มีฟังก์ชันสำหรับค้นหาชื่อที่ซ้ำกัน:

FSlint

แพคเกจ FSlint สำหรับอูบุนตูเน้นอินเตอร์เฟซแบบกราฟิก แต่จะมีการอธิบายในFSlint คำถามที่พบบ่อย/usr/share/fslint/fslint/อินเตอร์เฟซบรรทัดคำสั่งที่สามารถใช้ได้ผ่านทางโปรแกรมใน ใช้--helpตัวเลือกสำหรับเอกสารเช่น:

$ /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.

ตัวอย่างการใช้งาน:

$ /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

ขอบคุณสิ่งนี้ได้ผล ผลลัพธ์บางส่วนเป็นสีม่วงและบางส่วนเป็นสีเขียว คุณรู้หรือไม่ว่าสีที่แตกต่างมีความหมายว่าอย่างไร?
JD Isaacks

@John ดูเหมือนว่า FSlint ใช้ls -lเพื่อจัดรูปแบบเอาต์พุต คำถามนี้ควรอธิบายความหมายของสี
ændrük

FSlint มีการอ้างอิงจำนวนมาก
Navin

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

ตามที่ความคิดเห็นระบุไว้สิ่งนี้จะค้นหาโฟลเดอร์เช่นกัน นี่คือคำสั่งที่จะ จำกัด ไว้ในไฟล์:

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

ฉันเปลี่ยนวิธีแก้ปัญหาเพื่อให้ส่งคืนเส้นทางแบบเต็ม (สัมพัทธ์) ของรายการซ้ำทั้งหมด น่าเสียดายที่สมมติว่าชื่อพา ธ ไม่มี white-space เนื่องจากuniqไม่มีคุณสมบัติในการเลือกตัวคั่นฟิลด์อื่น
David Foerster

@DavidFoerster, rev 6 ของคุณได้รับการปรับปรุง แต่เกี่ยวกับความคิดเห็นของคุณที่นั่นตั้งแต่เมื่อsedล้าสมัย? ความลับ? แน่ใจ ล้าสมัย? ไม่ใช่ว่าฉันรู้ (และฉันเพิ่งค้นหาเพื่อตรวจสอบ)
cp.engr

@ cp.engr: sed ไม่ล้าสมัย มันกลายเป็นสิ่งที่ล้าสมัยหลังจากการเปลี่ยนแปลงของฉันอีกครั้ง
David Foerster

@DavidFoerster ล้าสมัยไม่ได้ดูเหมือนคำที่เหมาะสมสำหรับฉันแล้ว ฉันคิดว่า "การละทิ้ง" จะเหมาะกว่า ขอบคุณมากสำหรับการชี้แจง
cp.engr

@ cp.engr: ขอบคุณสำหรับคำแนะนำ! ฉันไม่ทราบคำว่า แต่ดูเหมือนว่าจะเหมาะกับสถานการณ์ที่ดีขึ้น
David Foerster

8

บันทึกสิ่งนี้ลงในไฟล์ชื่อ 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

จากนั้นทำให้ไฟล์ที่ปฏิบัติการได้:

chmod +x duplicates.py

ทำงานในเช่นนี้:

./duplicates.py ~/images

ควรส่งออกไฟล์คู่ที่มีชื่อไฟล์เหมือนกัน (1) เขียนในหลามคุณควรจะสามารถแก้ไขได้


ดูเหมือนว่าจะทำงานไม่ถูกต้อง ตรวจพบP001.ORFและP001 (1).ORFทำซ้ำและดูเหมือนว่าไฟล์ของฉัน 60% นั้นซ้ำซ้อนซึ่งผิดฉันค่อนข้างแน่ใจ fslintพบชื่อไฟล์ซ้ำกันจำนวนจริงซึ่งใกล้เคียงกับ 3%
Rolf

3

ฉันสมมติว่าคุณต้องการเห็น "รายการที่ซ้ำกัน" เหล่านี้จากนั้นจัดการด้วยตนเอง ถ้าเป็นเช่นนั้นรหัส bash4 นี้ควรทำในสิ่งที่คุณต้องการฉันคิดว่า

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

ดูhttp://mywiki.wooledge.org/BashGuide/Arrays#Associative_Arraysและ / หรือคู่มือทุบตีเพื่อขอความช่วยเหลือเกี่ยวกับไวยากรณ์อาร์เรย์ที่เชื่อมโยง


ฉันจะรันคำสั่งแบบนั้นในเทอร์มินัลได้อย่างไร นี่คือสิ่งที่ฉันต้องบันทึกเป็นไฟล์ก่อนและเรียกใช้ไฟล์หรือไม่
JD Isaacks

@John Isaacks คุณสามารถคัดลอก / วางมันลงในเทอร์มินัลหรือคุณสามารถวางไว้ในไฟล์และเรียกใช้เป็นสคริปต์ ทั้งสองกรณีจะประสบความสำเร็จเหมือนกัน
geirha

1

นี่คือ bname:

#!/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"

ทำให้ปฏิบัติการได้:

chmod a+x bname 

เรียกใช้:

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

มือโปร:

  • มันตรงไปตรงมาและเรียบง่ายจึงสามารถขยายได้
  • จัดการช่องว่างแท็บ linebreaks และเพจฟีดในชื่อไฟล์, afaik (สมมติว่าไม่มีสิ่งนั้นในชื่อนามสกุล)

Con:

  • มันจะค้นหาไฟล์เสมอและถ้าพบ a.gif สำหรับ a.jpg ก็จะพบ a.jpg สำหรับ a.gif ด้วย ดังนั้นสำหรับไฟล์ 10 ไฟล์ที่มีชื่อเดียวกันมันจะพบ 100 แมตช์ในตอนท้าย

0

การปรับปรุงสคริปต์ของ loevborg สำหรับความต้องการของฉัน (รวมเอาท์พุทที่จัดกลุ่ม, บัญชีดำ, ผลลัพธ์ที่สะอาดขึ้นขณะสแกน) ฉันกำลังสแกนไดรฟ์ 10TB ดังนั้นฉันจึงต้องการผลลัพธ์ที่สะอาดขึ้นเล็กน้อย

การใช้งาน:

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)
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.