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
- Jétais je cherche la même chose et jai trouvé cette réponse superuser.com/a/561207/218922
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
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
Où 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
jdupes
au lieu defdupes
vous pouvez simplement accéder àjdupes -nrL somedirectory/
, ce qui est beaucoup plus rapide.