Klasör hiyerarşisinde yinelenen dosya adlarını mı arıyorsunuz?


29

Adı verilen bir klasör var img, bu klasörde tümü görüntü içeren birçok alt klasör seviyesi var. Onları bir resim sunucusuna aktaracağım.

Normalde görüntüler (veya herhangi bir dosya), farklı bir dizin yolunda oldukları veya farklı bir uzantıya sahip oldukları sürece aynı ada sahip olabilirler. Ancak, bunları içe aktardığım resim sunucusu tüm resim adlarının benzersiz olmasını gerektirir (uzantılar farklı olsa bile).

Örneğin görüntüler background.pngve background.gifizin verilmez çünkü farklı uzantılara sahip olsalar bile yine de aynı dosya adına sahiptirler. Ayrı alt klasörlerde olsalar bile, benzersiz olmaları gerekir.

Bu yüzden img, aynı adı taşıyan dosyaların bir listesini bulmak için klasörde özyinelemeli bir araştırma yapıp yapamayacağımı merak ediyorum (uzantı hariç).

Bunu yapabilen bir komut var mı?


@DavidFoerster Haklısın! Bunun neden çift ​​dosyaları bulma (ve silme) kopyası olabileceğini düşündüğümü bilmiyorum , ama açıkça değil.
Eliah Kagan

Yanıtlar:


17

FSlint Fslint'i kurun , yinelenen adları bulma işlevini içeren çok yönlü bir yinelenen bulma aracıdır :

FSlint

Ubuntu için FSlint paketi, grafik arayüzü vurgular, ancak FSlint SSS’de açıklandığı gibi, programlarda bir komut satırı arayüzü bulunur /usr/share/fslint/fslint/. --helpBelgeleme seçeneğini kullanın , örneğin:

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

Örnek kullanım:

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

Teşekkürler bu çalıştı. Sonuçların bazıları mor, bazıları yeşil. Eldeki farklı renklerin ne anlama geldiğini biliyor musunuz?
JD Isaack,

@John FSlint, ls -lçıktısını biçimlendirmek için kullanıyor gibi görünüyor . Bu soru renklerin ne anlama geldiğini açıklamalıdır.
ændrük

FSlint'in çok fazla bağımlılığı var.
Navin

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

Yorumda belirtildiği gibi, bu klasörleri de bulacaktır. İşte dosyalara kısıtlama emri:

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

Çözümü değiştirdim, böylece tüm kopyaların tam (göreceli) yolunu döndürür. Ne yazık ki, yol adlarının beyaz boşluk içermediğini varsaymaktadır, çünkü uniqfarklı bir alan sınırlayıcı seçmek için bir özellik sunmamaktadır.
David Foerster

@DavidFoerster, 6 nolu revizyonunuz bir gelişme oldu, ancak yorumunuzla ilgili, ne zamandan beri sedkullanılmıyor? Esrarlı? Emin. Eski? Farkında olduğumdan değil. (Ve sadece kontrol etmek için aradım.)
cp.engr

@ cp.engr: sed eski değil. Başka bir değişiklikten sonra, bu aşılama modası geçmiş oldu.
David Foerster

@DavidFoerster, eski, o zaman bana doğru kelime gibi görünmüyor. Bence "mahrum" daha uygun olacaktı. Ne olursa olsun, açıklama için teşekkürler.
cp.engr

@ cp.engr: Öneriniz için teşekkürler! Bu kelimeyi bilmiyordum ama duruma daha iyi uyuyor gibi görünüyor.
David Foerster

8

Bunu adlı bir dosyaya kaydet 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

Ardından dosyayı çalıştırılabilir yapın:

chmod +x duplicates.py

Örneğin şöyle koş:

./duplicates.py ~/images

Aynı dosya adında (1) dosya çiftleri çıkarmalıdır. Python ile yazılmış, onu değiştirebilmelisiniz.


Düzgün çalışmıyor gibi görünüyor. Algılar P001.ORFve P001 (1).ORFyinelenir ve ayrıca dosyalarımın% 60'ının yinelemeler olduğunu düşünüyor gibi görünüyor ki bu oldukça eminim. fslint% 3'e yakın olan çok sayıda yinelenen dosya adı buldu.
Rolf

3

Sadece bu "kopyaları" görmeniz ve ardından el ile işlemeniz gerektiğini farz ediyorum. Eğer öyleyse, bu bash4 kodu bence istediğini yapmalı.

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

Bkz http://mywiki.wooledge.org/BashGuide/Arrays#Associative_Arrays ve / veya ilişkili dizi sözdizimi hakkında yardım bash kılavuzu.


Terminalde böyle bir komutu nasıl yürütebilirim? Bu, önce bir dosyaya kaydetmem ve dosyayı çalıştırmam gereken bir şey mi?
JD Isaacks,

@John Isaacks Terminale kopyalayıp yapıştırabilir veya bir dosyaya koyabilir ve bir komut dosyası olarak çalıştırabilirsiniz. Her iki durumda da aynı elde edecek.
geirha

1

Bu 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"

Çalıştırılabilir yap:

chmod a+x bname 

Çağır:

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

Pro:

  • Basit ve basittir, bu nedenle genişletilebilir.
  • Dosya isimlerinde boşluklar, sekmeler, satır çizgiler ve sayfa beslemelerini afaik olarak işler. (Uzantı adında böyle bir şey olmadığını varsayarak).

con:

  • Her zaman dosyanın kendisini bulur ve a.jpg için a.gif dosyasını bulursa, a.gif için a.jpg dosyasını da bulur. Böylece, aynı addaki 10 dosya için, sonunda 100 eşleşme bulur.

0

Benim ihtiyaçlarım için loevborg'un senaryosunun iyileştirilmesi (gruplandırılmış çıktı, kara liste, tarama sırasındaki daha temiz çıktı dahil). 10TB'lik bir sürücüyü tarıyordum, bu yüzden biraz daha temiz bir çıktıya ihtiyacım vardı.

Kullanımı:

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)
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.