Nach doppelten Dateinamen in der Ordnerhierarchie suchen?


29

Ich habe einen Ordner namens img, dieser Ordner hat viele Ebenen von Unterordnern, die alle Bilder enthalten. Ich werde sie in einen Image-Server importieren.

Normalerweise können Bilder (oder beliebige Dateien) denselben Namen haben, solange sie sich in einem anderen Verzeichnispfad befinden oder eine andere Erweiterung haben. Für den Image-Server, in den ich sie importiere, müssen jedoch alle Image-Namen eindeutig sein (auch wenn die Erweiterungen unterschiedlich sind).

Zum Beispiel die Bilder background.pngund background.gifwären nicht erlaubt, weil sie, obwohl sie unterschiedliche Erweiterungen haben, immer noch den gleichen Dateinamen haben. Auch wenn sie sich in separaten Unterordnern befinden, müssen sie eindeutig sein.

Daher frage ich mich, ob ich eine rekursive Suche im imgOrdner durchführen kann, um eine Liste von Dateien mit demselben Namen (ohne Erweiterung) zu finden.

Gibt es einen Befehl, der das kann?


@DavidFoerster Du hast recht! Ich habe keine Ahnung, warum ich dachte, dass dies ein Duplikat von So finden (und löschen) Sie doppelte Dateien sein könnte , aber es ist eindeutig nicht.
Eliah Kagan

Antworten:


17

FSlint Installieren Sie fslint ist ein vielseitiger Dublettenfinder, der eine Funktion zum Suchen von Dublettennamen enthält:

FSlint

Das FSlint-Paket für Ubuntu hebt die grafische Oberfläche hervor, aber wie in den FSlint-FAQ erläutert, ist eine Befehlszeilenschnittstelle über die Programme in verfügbar /usr/share/fslint/fslint/. Nutzen Sie die --helpOption zur Dokumentation, zB:

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

Anwendungsbeispiel:

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

Danke, das hat funktioniert. Einige der Ergebnisse sind in lila und andere in grün. Wissen Sie, was die verschiedenen Farben bedeuten?
JD Isaacks

@ John Es sieht so aus, als würde FSlint ls -lseine Ausgabe formatieren. Diese Frage sollte erklären, was die Farben bedeuten.
ændrük

FSlint hat viele Abhängigkeiten.
Navin

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

Wie der Kommentar besagt, werden hier auch Ordner gefunden. Hier ist der Befehl, um es auf Dateien zu beschränken:

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

Ich habe die Lösung so geändert, dass sie den vollständigen (relativen) Pfad aller Duplikate zurückgibt. Leider wird davon ausgegangen, dass Pfadnamen keine Leerzeichen enthalten, da uniqsie keine Funktion zur Auswahl eines anderen Feldtrennzeichens bieten.
David Foerster

@DavidFoerster, deine Version 6 war eine Verbesserung, aber was deinen Kommentar betrifft, seit wann ist er sedveraltet? Arkan? Sicher. Obsolet? Nicht dass ich wüsste. (Und ich habe gerade gesucht, um zu überprüfen.)
cp.engr

@ cp.engr: sed ist nicht veraltet. Die Anrufung ist nach einer weiteren Änderung obsolet geworden.
David Foerster

@ DavidFoerster, obsolet scheint mir dann nicht das richtige Wort zu sein. Ich denke, "umgangen" wäre eine bessere Passform. Egal, danke für die Klarstellung.
cp.engr

@ cp.engr: Danke für den Vorschlag! Ich kannte das Wort nicht, aber es scheint besser zur Situation zu passen.
David Foerster

8

Speichern Sie dies in einer Datei mit dem Namen 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

Dann machen Sie die Datei ausführbar:

chmod +x duplicates.py

Laufen Sie zB so ein:

./duplicates.py ~/images

Es sollten Dateipaare ausgegeben werden, die denselben Basisnamen haben (1). In Python geschrieben, sollten Sie es ändern können.


Es scheint nicht richtig zu funktionieren. Es erkennt P001.ORFund P001 (1).ORFals Duplikate und scheint auch zu denken, dass 60% meiner Dateien Duplikate sind, was falsch ist, da bin ich mir ziemlich sicher. fslintEs wurde eine realistische Anzahl doppelter Dateinamen gefunden, die nahe bei 3% liegt.
Rolf

3

Ich gehe davon aus, dass Sie nur diese "Duplikate" sehen und sie dann manuell bearbeiten müssen. Wenn ja, sollte dieser Bash4-Code tun, was Sie wollen, denke ich.

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

Weitere Informationen zur assoziativen Array-Syntax finden Sie unter http://mywiki.wooledge.org/BashGuide/Arrays#Associative_Arrays und / oder im Bash-Handbuch.


Wie führe ich einen solchen Befehl in einem Terminal aus? Muss ich das zuerst in einer Datei speichern und die Datei ausführen?
JD Isaacks

@ John Isaacks Sie können es kopieren / in das Terminal einfügen oder Sie können es in eine Datei einfügen und als Skript ausführen. In beiden Fällen wird das Gleiche erreicht.
Geirha

1

Das ist 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"

Mach es ausführbar:

chmod a+x bname 

Rufe es auf:

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

Profi:

  • Es ist unkompliziert und einfach, daher erweiterbar.
  • Behandelt Leerzeichen, Tabulatoren, Zeilenumbrüche und Seitenvorschübe in Dateinamen, afaik. (Unter der Annahme, dass der Name der Erweiterung nichts Ähnliches enthält).

Con:

  • Es findet immer die Datei selbst und wenn es a.gif für a.jpg findet, findet es auch a.jpg für a.gif. Für 10 Dateien mit demselben Basisnamen werden am Ende 100 Übereinstimmungen gefunden.

0

Verbesserung von Loevborgs Skript für meine Bedürfnisse (beinhaltet gruppierte Ausgabe, Blacklist, sauberere Ausgabe beim Scannen). Ich habe ein 10-TB-Laufwerk gescannt und brauchte eine etwas sauberere Ausgabe.

Verwendung:

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)
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.