Sinds kort heb ik de behoefte om veel duplicaten te verwijderen. Ik voeg drie of vier bestandssystemen samen, en ik wil dat de ruimte economisch wordt gebruikt. In eerste instantie leek fdupes het de beste tool voor de klus te zijn, maar ik kom steeds meer beperkingen tegen.

Beschouw het commando fdupes -rdN somedirectory/. Dit maakt een hash van alle bestanden in de submappen van een map.

En als het duplicaten tegenkomt, worden ze verwijderd, zodat er maar één kopie van alles is.

Maar wat als ik somedirectory/subdirectory1/somefile en er zijn in feite vier duplicaten, en het programma komt als eerste een van de duplicaten tegen? Vervolgens wordt somedirectory/subdirectory1/somefile verwijderd, wat ik niet wil.

Ik wil op de een of andere manier kunnen specificeren welke duplicaten ik wil behouden. En tot nu toe geen van de standaardprogrammas voor het omgaan met duplicaten (duff, FSLint) lijken automatisering van dat soort gedrag mogelijk te maken. Ik “zou liever niet mijn eigen draaien, dus daarom stel ik deze vraag.

Ik “zou graag zoiets willen schrijven

killdupes -rdN --keep=filesin,somedirectories,separated,by,commas somedirectory/ 

Reacties

antwoord

Hoewel de functionaliteit die u zoekt niet op voorraad is fdupes, heb ik fdupes (mijn vork heet jdupes) en heeft een aantal functies toegevoegd die dit probleem onder bepaalde omstandigheden kunnen oplossen. Voor voorbeeld, in het genoemde geval waarin u somedirectory/subdirectory1/somefile bij het automatisch verwijderen van duplicaten (de d en N schakelen samen) en er zijn geen afzonderlijke bestanden direct onder somedirectory, jdupes kan elk direct submappad worden ingevoerd met subdirectory1 eerst en de -O schakelaar (die bestanden eerst sorteert op opdrachtregelparametervolgorde):

jdupes -nrdNO somedirectory/subdirectory1 somedirectory/subdirectory2 somedirectory/subdirectory3

Dit verwijdert automatisch alle bestanden op één na in een dubbele set en garandeert dat als de set een bestand bevat in somedirectory/subdirectory1, dit het eerste is en automatisch het bewaarde bestand in de set wordt . Er zijn nog steeds flagrante grenzen aan deze benadering, zoals het feit dat een ander duplicaat in somedirectory/subdirectory1 mogelijk wordt bewaard in plaats van degene die u wilde behouden, maar in een groot aantal gevallen zoals het uwe, de jdupes optie voor parametervolgorde als tijdelijke oplossing is goed genoeg.

In de nabije toekomst ben ik van plan een filtersysteem toe te voegen aan jdupes die een enorme hoeveelheid controle mogelijk zal maken over het opnemen / uitsluiten van bestanden, het behoud van -N acties, en het toepassen van dergelijke “filterstacks” op een globale of per -parameter basis. Deze functie is hard nodig; Ik stel me zoiets voor om “niet-nul duplicaten recursief automatisch te verwijderen MAAR bewaar altijd somedirectory/subdirectory1/somefile zoals het is”:

jdupes -nrdN --filter=preserve:somedirectory/subdirectory1/somefile somedirectory/

Antwoord

Ik heb deze nergens anders gezien: zeg wat je wilt is dit. Je hebt / mnt / folder-tree-1 / mnt / folder-tree-2. Je wilt niet elke dupe verwijderen, maar als er een bestand bestaat in boom-2, en een identiek bestand bestaat in boom-1 met exact dezelfde pad en naam, verwijder het uit boom-2.

Waarschuwing: dit is nogal beknopt en als je dit probeert te kopiëren en plakken met beperkte shell-vaardigheden, wees dan voorzichtig.

fdupes -rn /mnt/folder-tree-1/ /mnt/folder-tree-2/ > dupes-all.txt fgrep /mnt/folder-tree-1/ dupes-all.txt | while read line do if grep -q "`echo $line | sed -e "s|^/mnt/folder-tree-1/|/mnt/folder-tree-2/|"`" dupes-all.txt then echo rm \"$(echo $line | sed -e "s|^/mnt/folder-tree-1/|/mnt/folder-tree-2//|")\" fi done > rm-v2-dupes.sh 

Of alles op één regel:

fdupes -rn /mnt/folder-tree-1/ /mnt/folder-tree-2/ > dupes-all.txt; fgrep /mnt/folder-tree-1/ dupes-all.txt | while read line; do if grep -q "`echo $line | sed -e "s|^/mnt/folder-tree-1/|/mnt/folder-tree-2/|"`" dupes-all.txt; then echo rm \"$(echo $line | sed -e "s|^/mnt/folder-tree-1/|/mnt/folder-tree-2/|")\"; fi; done > rm-v2-dupes.sh 

Inspecteer en voer daarna rm-v2-dupes.sh uit

Answer

Hoe zit het met het hard linken van de dubbele bestanden aan elkaar? Op die manier wordt de ruimte maar één keer gebruikt, maar ze bestaan nog steeds in alle paden. Het nadeel hiervan is dat hardlink-bestanden op hun plaats moeten worden gewijzigd (ze mogen alleen worden gewijzigd door het bestand te verwijderen en het opnieuw te maken met de nieuwe inhoud). De andere benadering is om de bestanden aan elkaar te koppelen, hoewel u dezelfde kwestie hebt om te beslissen welk “primaire” bestand is. Dit zou kunnen worden gedaan met het volgende script (merk op dat dit geen “bestandsnamen met spaties” behandelt.

fdupes --quiet --recurse --sameline somedirectory/ | while read SOURCE DESTS; do for DEST in $DESTS; do ln -f $SOURCE $DEST done done 

Reacties

  • Gebruik van jdupes in plaats van fdupes je kunt gewoon jdupes -nrL somedirectory/ gaan, wat enorm sneller is.
  • Typefout in de link naar jdupes. Gemakkelijke link: github.com/jbruchon/jdupes

Antwoord

Ik had dezelfde vraag.Als je veel duplicaten hebt, bewaart fdupes /my/directory/ -rdN het bestand met de oudste wijzigingsdatum, of als meerdere bestanden dezelfde wijzigingsdatum hebben, wordt het bestand dat het eerst gevonden is, behouden.

Als de wijzigingsdatum niet belangrijk voor u is, kunt u touch de bestanden in de directory die u wilt behouden. Als je ervoor kiest om touch ze met de huidige datum en tijd te geven, dan zal fdupes -rdNi degenen met de huidige datum behouden. Of u kunt touch bestanden bewaren met een datum eerder dan die van degene die u wilt verwijderen en fdupes -rdN gebruiken zoals normaal.

Als u de wijzigingsdatum wilt behouden, moet u een van de andere methoden gebruiken.

Antwoord

Gewoon om een draai te geven aan een eerder antwoord. Ik heb de volgende code meerdere keren gebruikt, waarbij ik een eerder antwoord enigszins heb gewijzigd met een simpele | grep om de map te isoleren waaruit ik wil verwijderen.

`fdupes -r -n -S /directory | grep /delete-from-directory | sed -r "s/^/rm \"/" | sed -r "s/$/\"/" >remove-duplicate-files.sh` 

Nogmaals, dit zal een sh-bestand aanmaken om alle vermelde bestanden te verwijderen, geen commentaarregels. Je kunt het bestand natuurlijk nog steeds bewerken om specifieke regels / bestanden die je wilt behouden te becommentariëren.

Een andere hint voor grote mappen is om fdupes naar een txt-bestand uit te voeren en vervolgens te experimenteren met | grep en | sed totdat ik de resultaat dat ik wil.

`fdupes -r -n -S /directory > duplicate-files.txt` `cat duplicate-files.txt | grep /delete-from-directory | sed -r "s/^/rm \"/" | sed -r "s/$/\"/" >remove-duplicate-files.sh` 

Antwoord

Gebruik sed om een shell-bestand te maken dat becommentarieerde commandos bevat om al je dubbele bestanden:

fdupes -r -n -S /directory | sed -r "s/^/#rm \"/" | sed -r "s/$/\"/" >remove-duplicate-files.sh 

De resulterende remove-duplicate-files.sh fil Bij die we zojuist hebben gemaakt, wordt elke regel van commentaar voorzien. Verwijder commentaar bij de bestanden die u wilt verwijderen. Voer vervolgens sh remove-duplicate-files.sh uit. Voila!

UPDATE

Nou, als je niet “alleen bestanden in bepaalde mappen wilt verwijderen, is het zo simpel als dit :

fdupes -S /directory|sed "/^$/d" |sed -r "s/^[0-9]/#&/" > duple_list python exclude_duplicates.py -f /path/to/dupe_list --delimiter="#" --keep=/full/path/to/protected/directory1,/full/path/to/protected/directory2\ with\ spaces\ in\ path >remove-duplicate-files-keep-protected.sh 

Waarbij exclude_duplicates.py is:

 #/usr/bin/python # -*- coding: utf-8 -*- # exclude_duplicates.py """ THE SCRIPT DOESN"T DELETE ANYTHING, IT ONLY GENERATES TEXT OUTPUT. Provided a list of duplicates, such as fdupes or fslint output, generate a bash script that will have all duplicates in protected directories commented out. If none of the protected duplicates are found in a set of the same files, select a random unprotected duplicate for preserving. Each path to a file will be transformed to an `rm "path"` string which will be printed to standard output. """ from optparse import OptionParser parser = OptionParser() parser.add_option("-k", "--keep", dest="keep", help="""List of directories which you want to keep, separated by commas. \ EXAMPLE: exclude_duplicates.py --keep /path/to/directory1,/path/to/directory\ with\ space\ in\ path2""", metavar="keep" ) parser.add_option("-d", "--delimiter", dest="delimiter", help="Delimiter of duplicate file groups", metavar="delimiter" ) parser.add_option("-f", "--file", dest="file", help="List of duplicate file groups, separated by delimiter, for example, fdupes or fslint output.", metavar="file" ) (options, args) = parser.parse_args() directories_to_keep = options.keep.split(",") file = options.file delimiter = options.delimiter pretty_line = "\n#" + "-" * 35 print "#/bin/bash" print "#I will protect files in these directories:\n" for d in directories_to_keep: print "# " + d print pretty_line protected_set = set() group_set = set() def clean_set(group_set, protected_set, delimiter_line): not_protected_set = group_set - protected_set while not_protected_set: if len(not_protected_set) == 1 and len(protected_set) == 0: print "#randomly selected duplicate to keep:\n#rm "%s"" % not_protected_set.pop().strip("\n") else: print "rm "%s"" % not_protected_set.pop().strip("\n") for i in protected_set: print "#excluded file in protected directory:\n#rm "%s"" % i.strip("\n") print "\n#%s" % delimiter_line file = open(file, "r") for line in file.readlines(): if line.startswith(delimiter): clean_set(group_set, protected_set, line) group_set, protected_set = set(), set() else: group_set = group_set|{line} for d in directories_to_keep: if line.startswith(d): protected_set = protected_set|{line} else: if line: clean_set(group_set, protected_set, line)  

Het resulterende remove-duplicate-files-keep-protected.sh -bestand dat we zojuist hebben gemaakt, zullen alle bestanden uit beschermde mappen hebben becommentarieerd. Open dit bestand in uw favoriete teksteditor, controleer of alles in orde is. Voer het vervolgens uit. Voila (sic)!

Opmerkingen

  • ik dacht hieraan, maar het ‘ is niet voldoende geautomatiseerd. Stom genoeg veroorzaakte ik gegevensverlies met deze methode toen omgaan met duplicaten verspreid over meerdere bestandssystemen … er is ‘ s geen manier om een prioriteit toe te wijzen, gezien de uitvoer van fdup es. eigenlijk had ik 10.000 bestanden met de hand moeten doorzoeken om dat gegevensverlies te voorkomen … dus nee bedankt … in feite is dat gegevensverlies juist de reden dat ik deze vraag stelde.
  • @ixtmixilix, nou ja, handmatige methode is afhankelijk van de aandacht van de gebruiker, hier is ‘ niets nieuws. Als je iets meer geautomatiseerd wilt, bekijk dan een bijgewerkt antwoord hierboven.

Antwoord

Hoe zit het met zoiets?

#!/bin/bash DUPE_SEARCH_DIR=somedir/ PREFERRED_DIRS=("somedir/subdir1" "somedir/subdir2") DUPE_FILE=/tmp/`basename $0`_found-duplicates delete_dupes() { while read line ; do if [ -n "$line" ] ; then matched=false for pdir in "${PREFERRED_DIRS[@]}" ; do if [[ $line == $pdir/* ]] ; then matched=true break fi done if ! $matched ; then rm -v "$line" fi fi done < "$DUPE_FILE" } cleanup() { rm -f $DUPE_FILE } trap cleanup EXIT # get rid of normal dupes, preserve first & preserve preferred fdupes -rf "$DUPE_SEARCH_DIR" > $DUPE_FILE delete_dupes # get rid of preserve dupes, preserve preferred fdupes -r "$DUPE_SEARCH_DIR" > "$DUPE_FILE" delete_dupes 

Antwoord

Vanaf het Apple Filesystem (APFS), een andere oplossing is om de bestanden te bewaren, ze te ontdubbelen en geen invloed te hebben op het schijfgebruik. Zie Vervang bestaande dubbele bestanden op APFS door klonen

Geef een reactie

Het e-mailadres wordt niet gepubliceerd. Vereiste velden zijn gemarkeerd met *