Шукати дублюючі назви файлів у ієрархії папок?


29

У мене папка називається img, ця папка має багато рівнів підпапок, усі з яких містять зображення. Я збираюся імпортувати їх на сервер зображень.

Зазвичай зображення (або будь-які файли) можуть мати те саме ім’я, якщо вони знаходяться в іншому контурі до каталогу або мають інше розширення. Однак сервер зображень, в який я імпортую, вимагає, щоб усі імена зображень були унікальними (навіть якщо розширення різні).

Наприклад зображення background.pngі background.gifне буде розв'язано , тому що незважаючи на те, що вони мають різні розширення , вони по- , як і раніше мають таке ж ім'я файлу. Навіть якщо вони знаходяться в окремих підпапках, вони все одно повинні бути унікальними.

Тож мені цікаво, чи можу я виконати рекурсивний пошук у imgпапці, щоб знайти список файлів із однаковою назвою (крім розширення).

Чи є команда, яка може це зробити?


@DavidFoerster Ти маєш рацію! Я поняття не маю, чому я думав, що це може бути дублікат того, як знайти (і видалити) дублікати файлів , але явно це не так.
Елія Каган

Відповіді:


17

FSlint Встановіть fslint - універсальний пошук дублікатів, який включає функцію пошуку дублікатів імен:

FSlint

Пакет FSlint для Ubuntu підкреслює графічний інтерфейс, але, як пояснено у FSlint FAQ, інтерфейс командного рядка доступний через програми в /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 має багато залежностей.
Навін

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

Я змінив рішення, щоб воно повернуло повний (відносний) шлях усіх дублікатів. На жаль, це передбачає, що назви шляхів не містять пробілів, оскільки uniqне містять можливості вибору іншого роздільника поля.
Девід Фоерстер

@DavidFoerster, ваша версія 6 була вдосконаленням, але щодо вашого коментаря там, коли коли це sedзастаріло? Таємничий? Звичайно. Застарілий? Не те, що мені відомо. (І я просто шукав, щоб перевірити.)
cp.engr

@ cp.engr: sed не застаріло. Це виклик застаріло після чергової зміни.
Девід Фоерстер

@DavidFoerster, застаріле не здається мені правильним словом. Я думаю, що "ухилятися" було б краще. Незалежно, дякую за уточнення.
cp.engr

@ cp.engr: Дякую за пропозицію! Я не знав цього слова, але, здається, він краще відповідає ситуації.
Девід Фоерстер

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). Написаний python, ви повинні мати змогу змінити його.


Схоже, це не працює належним чином. Він виявляє P001.ORFі P001 (1).ORFяк дублікати, а також, здається, думає, що 60% моїх файлів - це дублікати, що неправильно, я досить впевнений. fslintзнайдено реальну кількість повторюваних імен файлів, що близько 3%.
Рольф

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 та / або посібник з bash щодо довідки про синтаксис асоціативного масиву.


Як виконати таку команду в терміналі? Це щось, що мені потрібно спершу зберегти у файл та виконати файл?
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

Про:

  • Це просто і просто, тому розширюється.
  • Обробляє прогони, вкладки, переривання рядків та стрічки сторінок у назви файлів, afaik. (Якщо в розширенні-імені немає подібного).

Con:

  • Він завжди знаходить сам файл, і якщо він знайде a.gif для a.jpg, він знайде a.jpg і для a.gif. Тож для 10 файлів з однаковою базовою назвою він знаходить у підсумку 100 збігів.

0

Вдосконалення сценарію loevborg, для моїх потреб (включає груповий вихід, чорний список, більш чистий вихід під час сканування). Я сканував накопичувач на 10 ТБ, тому мені знадобився трохи більш чистий вихід.

Використання:

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)
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.