Rechercher des noms de fichiers en double dans la hiérarchie des dossiers?

29

J'ai un dossier appelé img, ce dossier a plusieurs niveaux de sous-dossiers, qui contiennent tous des images. Je vais les importer dans un serveur d'images.

Normalement, les images (ou tout fichier) peuvent avoir le même nom tant qu'elles se trouvent dans un chemin de répertoire différent ou ont une extension différente. Cependant, le serveur d'images dans lequel je les importe nécessite que tous les noms d'images soient uniques (même si les extensions sont différentes).

Par exemple, les images background.pnget background.gifne seraient pas autorisées car même si elles ont des extensions différentes, elles ont toujours le même nom de fichier. Même s'ils se trouvent dans des sous-dossiers distincts, ils doivent toujours être uniques.

Je me demande donc si je peux faire une recherche récursive dans le imgdossier pour trouver une liste de fichiers qui portent le même nom (hors extension).

Y a-t-il une commande qui peut le faire?

JD Isaacks
la source
@DavidFoerster Vous avez raison! Je n'ai aucune idée pourquoi j'avais pensé que cela pourrait être un doublon de Comment trouver (et supprimer) des fichiers en double , mais ce n'est clairement pas le cas.
Eliah Kagan

Réponses:

17

FSlint Installer fslint est un chercheur de doublons polyvalent qui comprend une fonction pour trouver des noms en double:

FSlint

Le package FSlint pour Ubuntu met l'accent sur l'interface graphique, mais comme expliqué dans la FAQ FSlint, une interface de ligne de commande est disponible via les programmes dans /usr/share/fslint/fslint/. Utilisez l' --helpoption pour la documentation, par exemple:

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

Exemple d'utilisation:

$ /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
la source
Merci, cela a fonctionné. Certains des résultats sont en violet et certains en vert. Savez-vous tout de suite ce que signifient les différentes couleurs?
JD Isaacks
@John Il semble que FSlint utilise ls -lpour formater sa sortie. Cette question devrait expliquer ce que signifient les couleurs.
ændrük
FSlint a beaucoup de dépendances.
Navin
31
find . -mindepth 1 -printf '%h %f\n' | sort -t ' ' -k 2,2 | uniq -f 1 --all-repeated=separate | tr ' ' '/'

Comme l'indique le commentaire, cela trouvera également des dossiers. Voici la commande pour le restreindre aux fichiers:

find . -mindepth 1 -type f -printf '%p %f\n' | sort -t ' ' -k 2,2 | uniq -f 1 --all-repeated=separate | cut -d' ' -f1
ojblass
la source
J'ai changé la solution pour qu'elle renvoie le chemin complet (relatif) de tous les doublons. Malheureusement, il suppose que les noms de chemin ne contiennent pas d'espace blanc car uniqne fournit pas de fonctionnalité pour sélectionner un délimiteur de champ différent.
David Foerster
@DavidFoerster, votre version 6 était une amélioration, mais en ce qui concerne votre commentaire, depuis quand est-il sedobsolète? Ésotérique? Sûr. Obsolète? Pas que je sache. (Et je viens de chercher pour vérifier.)
cp.engr
@ cp.engr: sed n'est pas obsolète. Son invocation est devenue obsolète après un autre changement.
David Foerster
@DavidFoerster, obsolète ne me semble donc pas le bon mot. Je pense que "évité" serait un meilleur choix. Quoi qu'il en soit, merci d'avoir clarifié.
cp.engr
@ cp.engr: Merci pour la suggestion! Je ne connaissais pas ce mot mais il semble mieux correspondre à la situation.
David Foerster
8

Enregistrez-le dans un fichier nommé 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

Rendez ensuite le fichier exécutable:

chmod +x duplicates.py

Exécuter par exemple comme ceci:

./duplicates.py ~/images

Il doit générer des paires de fichiers portant le même nom de base (1). Écrit en python, vous devriez pouvoir le modifier.

Loevborg
la source
Cela ne semble pas fonctionner correctement. Il détecte P001.ORFet en P001 (1).ORFtant que doublons et il semble également penser que 60% de mes fichiers sont des doublons, ce qui est faux, je suis presque sûr. fslinttrouvé un nombre réel de noms de fichiers en double qui est proche de 3%.
Rolf
3

Je suppose que vous n'avez besoin que de voir ces "doublons", puis de les gérer manuellement. Si c'est le cas, ce code bash4 devrait faire ce que vous voulez, je pense.

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

Voir http://mywiki.wooledge.org/BashGuide/Arrays#Associative_Arrays et / ou le manuel bash pour obtenir de l'aide sur la syntaxe du tableau associatif.

geirha
la source
Comment exécuter une commande comme ça dans un terminal? Est-ce quelque chose que je dois d'abord enregistrer dans un fichier et exécuter le fichier?
JD Isaacks
@John Isaacks Vous pouvez le copier / coller dans le terminal ou le mettre dans un fichier et l'exécuter en tant que script. Dans les deux cas, le résultat sera le même.
geirha
1

C'est 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"

Rendez-le exécutable:

chmod a+x bname 

Invoquez-le:

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

Pro:

  • C'est simple et simple, donc extensible.
  • Gère les blancs, les tabulations, les sauts de ligne et les sauts de page dans les noms de fichiers, afaik. (En supposant que rien dans le nom de l'extension).

Con:

  • Il trouve toujours le fichier lui-même, et s'il trouve a.gif pour a.jpg, il trouvera également a.jpg pour a.gif. Donc, pour 10 fichiers du même nom de base, il trouve 100 correspondances à la fin.
Utilisateur inconnu
la source
0

Amélioration du script de Loevborg, pour mes besoins (inclut une sortie groupée, une liste noire, une sortie plus propre lors de la numérisation). Je numérisais un lecteur de 10 To, j'avais donc besoin d'une sortie un peu plus propre.

Usage:

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
la source