¿Buscar nombres de archivos duplicados dentro de la jerarquía de carpetas?

29

Tengo una carpeta llamada img, esta carpeta tiene muchos niveles de subcarpetas, todas las cuales contienen imágenes. Los voy a importar a un servidor de imágenes.

Normalmente, las imágenes (o cualquier archivo) pueden tener el mismo nombre siempre que estén en una ruta de directorio diferente o tengan una extensión diferente. Sin embargo, el servidor de imágenes en el que los estoy importando requiere que todos los nombres de imágenes sean únicos (incluso si las extensiones son diferentes).

Por ejemplo, las imágenes background.pngy background.gifno se le permitiría, porque a pesar de que tienen diferentes extensiones que todavía tienen el mismo nombre de archivo. Incluso si están en subcarpetas separadas, aún deben ser únicas.

Entonces, me pregunto si puedo hacer una búsqueda recursiva en la imgcarpeta para encontrar una lista de archivos que tengan el mismo nombre (sin incluir la extensión).

¿Hay un comando que pueda hacer esto?

JD Isaacks
fuente
@DavidFoerster ¡Tienes razón! No tengo idea de por qué pensé que esto podría ser un duplicado de Cómo encontrar (y eliminar) archivos duplicados , pero claramente no lo es.
Eliah Kagan

Respuestas:

17

FSlint Instalar fslint es un buscador de duplicados versátil que incluye una función para encontrar nombres duplicados:

FSlint

El paquete FSlint para Ubuntu enfatiza la interfaz gráfica, pero como se explica en las preguntas frecuentes de FSlint, hay una interfaz de línea de comandos disponible a través de los programas en /usr/share/fslint/fslint/. Use la --helpopción de documentación, por ejemplo:

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

Ejemplo de uso:

$ /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
ændrük
fuente
Gracias esto funcionó. Algunos de los resultados están en morado y otros en verde. ¿Sabes de primera mano qué significan los diferentes colores?
JD Isaacks
@ John Parece que FSlint está usando ls -lpara formatear su salida. Esta pregunta debería explicar qué significan los colores.
ændrük
FSlint tiene muchas dependencias.
Navin
31
find . -mindepth 1 -printf '%h %f\n' | sort -t ' ' -k 2,2 | uniq -f 1 --all-repeated=separate | tr ' ' '/'

Como dice el comentario, también encontrará carpetas. Aquí está el comando para restringirlo a archivos:

find . -mindepth 1 -type f -printf '%p %f\n' | sort -t ' ' -k 2,2 | uniq -f 1 --all-repeated=separate | cut -d' ' -f1
ojblass
fuente
Cambié la solución para que devuelva la ruta completa (relativa) de todos los duplicados. Desafortunadamente, se supone que los nombres de ruta no contienen espacios en blanco porque uniqno proporcionan una función para seleccionar un delimitador de campo diferente.
David Foerster
@DavidFoerster, su rev ​​6 fue una mejora, pero con respecto a su comentario allí, ¿desde cuándo es sedobsoleto? ¿Arcano? Seguro. ¿Obsoleto? No que yo supiese. (Y solo busqué para verificar).
cp.engr
@ cp.engr: sed no está obsoleto. Su invocación se volvió obsoleta después de otro cambio mío.
David Foerster
@DavidFoerster, obsoleto no me parece la palabra correcta, entonces. Creo que "obviado" sería mejor. De todos modos, gracias por aclarar.
cp.engr
@ cp.engr: ¡Gracias por la sugerencia! No conocía esa palabra, pero parece encajar mejor con la situación.
David Foerster
8

Guarda esto en un archivo llamado 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

Luego haga que el archivo sea ejecutable:

chmod +x duplicates.py

Ejecutar, por ejemplo, así:

./duplicates.py ~/images

Debería generar pares de archivos que tengan el mismo nombre base (1). Escrito en python, deberías poder modificarlo.

loevborg
fuente
No parece funcionar correctamente. Detecta P001.ORFy P001 (1).ORFcomo duplicados y también parece pensar que el 60% de mis archivos son duplicados, lo cual está mal, estoy bastante seguro. fslintencontró un número real de nombres de archivo duplicados que está cerca del 3%.
Rolf
3

Supongo que solo necesita ver estos "duplicados", luego manejarlos manualmente. Si es así, este código bash4 debería hacer lo que quieras, creo.

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

Consulte http://mywiki.wooledge.org/BashGuide/Arrays#Associative_Arrays y / o el manual de bash para obtener ayuda sobre la sintaxis de matriz asociativa.

geirha
fuente
¿Cómo ejecuto un comando como ese en una terminal? ¿Es esto algo que necesito guardar primero en un archivo y ejecutar el archivo?
JD Isaacks
@ John Isaacks Puede copiarlo / pegarlo en el terminal o puede ponerlo en un archivo y ejecutarlo como un script. Cualquiera de los casos logrará lo mismo.
geirha
1

Este es 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"

Hazlo ejecutable:

chmod a+x bname 

Invocarlo:

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

Pro:

  • Es sencillo y simple, por lo tanto extensible.
  • Maneja espacios en blanco, pestañas, saltos de línea y avances de página en nombres de archivo, afaik. (Suponiendo que no haya tal cosa en el nombre de la extensión).

Estafa:

  • Siempre encuentra el archivo en sí mismo, y si encuentra a.gif para a.jpg, también encontrará a.jpg para a.gif. Entonces, para 10 archivos del mismo nombre base, encuentra 100 coincidencias al final.
usuario desconocido
fuente
0

Mejora al script de loevborg, para mis necesidades (incluye salida agrupada, lista negra, salida más limpia durante el escaneo). Estaba escaneando una unidad de 10TB, así que necesitaba una salida un poco más limpia.

Uso:

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)
skoczen
fuente