Récemment, jai besoin de supprimer beaucoup de doublons. Je fusionne trois ou quatre systèmes de fichiers et je souhaite que lespace soit utilisé de manière économique. Au début, fdupes semblait être le meilleur outil pour le travail, mais je suis de plus en plus confronté à des limitations.

Considérez la commande fdupes -rdN somedirectory/. Cela fait un hachage de tous les fichiers dans les sous-répertoires dun certain répertoire.

Et quand il rencontre des doublons, il les supprime, de sorte quil ny ait quune seule copie de tout.

Mais que faire si je veux garder somedirectory/subdirectory1/somefile et il y a, en fait, quatre doublons, et le programme rencontre lun des doublons en premier? Ensuite, il supprime somedirectory/subdirectory1/somefile, ce que je ne veux pas.

Je veux pouvoir spécifier, dune manière ou dune autre, quels doublons conserver. Et pour linstant, aucun des programmes standard pour traiter les doublons (duff, FSLint) semblent permettre lautomatisation de ce genre de comportement. Je préférerais ne pas lancer le mien, cest pourquoi je pose cette question.

Je « voudrais pouvoir écrire quelque chose comme

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

Commentaires

Alors que la fonctionnalité que vous recherchez nest pas disponible en stock fdupes, jai bifurqué fdupes (mon fork sappelle jdupes) et a ajouté quelques fonctionnalités qui peuvent résoudre ce problème dans certaines circonstances. Pour exemple, dans le cas indiqué où vous souhaitez conserver somedirectory/subdirectory1/somefile lors de la suppression automatique des doublons (les commutateurs d et N ensemble) et il ny a pas de fichiers séparés immédiatement sous somedirectory, jdupes peut être alimenté chaque chemin de sous-répertoire immédiat avec subdirectory1 en premier et le -O commutateur (qui trie dabord les fichiers par ordre des paramètres de ligne de commande):

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

Ceci supprimera automatiquement tous les fichiers sauf un dans un ensemble en double et garantira que si lensemble contient un fichier dans somedirectory/subdirectory1, il sera le premier, devenant ainsi automatiquement le fichier conservé dans lensemble . Il y a encore des limites flagrantes à cette approche comme le fait quun autre doublon dans somedirectory/subdirectory1 puisse être conservé au lieu de celui que vous vouliez conserver, mais dans un bon nombre de cas comme le vôtre, loption dordre des paramètres jdupes comme solution de contournement est suffisante.

Dans un proche avenir, je prévois dajouter un système de filtrage à jdupes qui permettra un contrôle énorme sur linclusion / exclusion des fichiers, la préservation des actions -N et lapplication de ces « piles de filtres » sur un plan global ou par – base de paramètres. Cette fonctionnalité est cruellement nécessaire; Jimagine quelque chose comme ceci pour « supprimer automatiquement les doublons non nuls de manière récursive MAIS toujours préserver somedirectory/subdirectory1/somefile tel quel »:

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

Réponse

Je nai vu celui-ci nulle part ailleurs: dites ce que vous voulez, cest ceci. Vous avez / mnt / folder-tree-1 / mnt / folder-tree-2. Vous ne voulez pas supprimer chaque dupe, mais si un fichier existe dans tree-2, et quun fichier identique existe dans tree-1 avec exactement le même chemin et nom, supprimez-le de tree-2.

Attention: ceci est assez laconique et si vous essayez de copier-coller ceci avec des compétences de shell limitées, soyez prudent.

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 

Ou tout sur une seule ligne:

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 

Ensuite, inspectez et exécutez rm-v2-dupes.sh

Réponse

Quen est-il de la liaison permanente des fichiers en double? De cette façon, lespace nest utilisé quune seule fois, mais ils existent toujours dans tous les chemins. Le hic, cest que les fichiers liés en dur doivent être modifiés sur place (ils ne doivent être modifiés quen supprimant le fichier et en le recréant avec le nouveau contenu). Lautre approche consiste à créer un lien symbolique entre les fichiers, bien que vous ayez le même problème de décider quel est le fichier « principal ». Cela pourrait être fait avec le script suivant (mais notez que cela ne gère pas les noms de fichiers contenant des espaces).

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

Commentaires

  • Utilisation de jdupes au lieu de fdupes vous pouvez simplement accéder à jdupes -nrL somedirectory/, ce qui est beaucoup plus rapide.
  • Une faute de frappe dans le lien vers jdupes. Lien pratique: github.com/jbruchon/jdupes

Réponse

Javais la même question.Si vous avez de nombreux doublons, fdupes /my/directory/ -rdN conserve le fichier avec la date de modification la plus ancienne, ou si plusieurs fichiers ont la même date de modification, alors celui trouvé en premier.

Si la date de modification nest pas importante pour vous, vous pouvez touch les fichiers dans le répertoire que vous souhaitez conserver. Si vous choisissez de les touch avec la date et lheure actuelles, fdupes -rdNi conservera celles avec la date actuelle. Ou vous pouvez touch conserver les fichiers dont la date est antérieure à celle de ceux que vous souhaitez supprimer et utiliser fdupes -rdN comme dhabitude.

Si vous avez besoin de conserver la date de modification, vous devrez utiliser lune des autres méthodes.

Réponse

Juste pour ajouter une touche à une réponse précédente. Jai utilisé le code suivant plusieurs fois, en modifiant légèrement une réponse précédente avec un simple | grep pour isoler le dossier dont je souhaite supprimer.

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

Encore une fois, cela créera un fichier sh pour supprimer tous les fichiers répertoriés, pas de lignes commentées. Bien sûr, vous pouvez toujours modifier le fichier pour commenter les lignes / fichiers spécifiques que vous souhaitez conserver.

Un autre conseil pour les grands répertoires est dexécuter fdupes dans un fichier txt, puis dexpérimenter avec | grep et | sed jusquà obtenir le résultat que je veux.

`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` 

Réponse

Utilisez sed pour créer un fichier shell qui contiendra des commandes commentées pour supprimer chacun de vos fichiers en double:

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

Le remove-duplicate-files.sh fil e que nous venons de créer aura chaque ligne commentée. Décommentez les fichiers que vous souhaitez supprimer. Exécutez ensuite sh remove-duplicate-files.sh . Voila!

UPDATE

Eh bien, si vous ne voulez pas supprimer des fichiers uniquement dans certains répertoires, cest aussi simple que ceci :

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 

exclude_duplicates.py est:

 #/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)  

Le résultat remove-duplicate-files-keep-protected.sh que nous venons de créer aura tous les fichiers des répertoires protégés commentés. Ouvrez ce fichier dans votre éditeur de texte préféré, vérifiez que tout va bien. Ensuite, exécutez-le. Voila (sic)!

Commentaires

  • Jy ai pensé, mais ‘ nest pas assez automatisé. Bêtement, jai causé une perte de données avec cette méthode lorsque traiter les doublons espacés sur plusieurs systèmes de fichiers … il ny a ‘ aucun moyen dattribuer une priorité, étant donné la sortie de fdup es. en gros, jaurais dû parcourir 10000 fichiers à la main pour éviter cette perte de données … donc, non merci … en fait, cette perte de données est la raison même pour laquelle jai posé cette question.
  • @ixtmixilix, eh bien, la méthode manuelle dépend de lattention de lutilisateur, ici ‘ rien de nouveau. Si vous voulez quelque chose de plus automatisé, consultez une réponse mise à jour ci-dessus.

Réponse

Et quelque chose comme ça?

#!/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 

Réponse

À partir du système de fichiers Apple (APFS), une autre solution est de conserver les fichiers, de les dédupliquer et de navoir aucun impact sur lutilisation du disque. Voir Remplacer les fichiers en double existants sur APFS par des clones

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *