Recientemente, tuve la necesidad de eliminar muchos duplicados. Estoy fusionando tres o cuatro sistemas de archivos y quiero que el espacio se utilice de forma económica. Al principio, fdupes parecía la mejor herramienta para el trabajo, pero cada vez tengo más limitaciones.

Considere el comando fdupes -rdN somedirectory/. Esto hace un hash de todos los archivos en los subdirectorios de algún directorio.

Y cuando encuentra duplicados, los borra, por lo que solo hay una copia de todo.

Pero, ¿y si quiero mantener somedirectory/subdirectory1/somefile y hay, de hecho, cuatro duplicados, y el programa encuentra uno de los duplicados primero? Luego borra somedirectory/subdirectory1/somefile, que no quiero.

Quiero poder especificar, de alguna forma, qué duplicados conservar. Y hasta ahora, ninguno de los programas estándar para tratar con duplicados (duff, FSLint) parecen permitir la automatización de ese tipo de comportamiento. Preferiría no lanzar el mío propio, por eso es que estoy haciendo esta pregunta.

Me gustaría poder escribir algo como

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

Comentarios

Respuesta

Si bien la funcionalidad que busca no está disponible en stock fdupes, bifurqué fdupes (mi bifurcación se llama jdupes) y agregué algunas características que pueden resolver este problema en ciertas circunstancias. Para ejemplo, en el caso indicado en el que desea mantener somedirectory/subdirectory1/somefile cuando se borran automáticamente los duplicados (los interruptores d y N juntos) y no hay archivos separados inmediatamente debajo de somedirectory, jdupes se puede alimentar a cada ruta de subdirectorio inmediata con subdirectory1 primero y la -O conmutador (que ordena los archivos por orden de parámetros de la línea de comandos primero):

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

Este eliminará automáticamente todos los archivos menos uno en un conjunto duplicado y garantizará que si el conjunto contiene un archivo en somedirectory/subdirectory1, será el primero, convirtiéndose automáticamente en el archivo preservado en el conjunto . Todavía existen límites evidentes para este enfoque, como el hecho de que se podría conservar otro duplicado en somedirectory/subdirectory1 en lugar del que deseaba conservar, pero en un buen número de casos como el suyo, la opción de orden de parámetro jdupes como solución alternativa es suficientemente buena.

En un futuro cercano, planeo agregar un sistema de filtrado a jdupes que permitirá una gran cantidad de control sobre la inclusión / exclusión de archivos, la preservación de -N acciones y la aplicación de tales «pilas de filtros» en un global o por -Base de parámetros. Esta característica es muy necesaria; Imagino algo como esto para «eliminar automáticamente los duplicados distintos de cero de forma recursiva, PERO siempre conservar somedirectory/subdirectory1/somefile tal cual»:

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

Respuesta

No vi este en ningún otro lugar: Di lo que quieres es esto. Tienes / mnt / folder-tree-1 / mnt / folder-tree-2. No desea eliminar todos los duplicados, pero si existe un archivo en el árbol-2 y existe un archivo idéntico en el árbol-1 con exactamente el mismo ruta y nombre, elimínelo del árbol-2.

Advertencia: esto es bastante conciso y si intenta copiar y pegar esto con habilidades limitadas de shell, tenga cuidado.

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 

O todo en una línea:

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 

Luego, inspeccione y ejecute rm-v2-dupes.sh

Respuesta

¿Qué hay de vincular los archivos duplicados juntos? De esa manera, el espacio solo se usa una vez, pero aún existen en todos los caminos. El problema con esto es que los archivos con vínculos fijos deben modificarse en su lugar (solo deben modificarse eliminando el archivo y recreándolo con el nuevo contenido). El otro enfoque es vincular simbólicamente los archivos, aunque tiene el mismo problema de decidir cuál es el archivo «principal». Esto se puede hacer con el siguiente script (aunque tenga en cuenta que esto no maneja nombres de archivo que contengan espacios).

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

Comentarios

  • Usando jdupes en lugar de fdupes simplemente puede ir a jdupes -nrL somedirectory/ que es muchísimo más rápido.
  • Error tipográfico en el enlace a jdupes. Enlace de conveniencia: github.com/jbruchon/jdupes

Responder

Tenía la misma pregunta.Si tiene muchos duplicados fdupes /my/directory/ -rdN mantiene el archivo con la fecha de modificación más antigua, o si varios archivos tienen la misma fecha de modificación, entonces el que se encontró primero.

Si la fecha de modificación no es importante para usted, puede touch los archivos en el directorio que desea conservar. Si elige touch con la fecha y hora actuales, entonces fdupes -rdNi mantendrá las que tengan la fecha actual. O puede touch conservar los archivos con una fecha anterior a la de los que desea eliminar y usar fdupes -rdN como de costumbre.

Si necesita mantener la fecha de modificación, deberá utilizar uno de los otros métodos.

Responder

Solo para agregar un giro a una respuesta anterior. He utilizado el siguiente código varias veces, modificando ligeramente una respuesta anterior con un simple | grep para aislar la carpeta de la que quiero eliminar.

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

De nuevo, esto creará un archivo sh para eliminar todos los archivos enumerados, sin líneas comentadas. Por supuesto, aún puede editar el archivo para comentar líneas / archivos específicos que desea conservar.

Otra sugerencia para directorios grandes es ejecutar fdupes en un archivo txt, luego experimentar con | grep y | sed hasta obtener el resultado que quiero.

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

Responder

Utilice sed para crear un archivo de shell que contendrá comandos comentados para eliminar cada uno de sus archivos duplicados:

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

El remove-duplicate-files.sh fil El que acabamos de crear tendrá cada línea comentada. Descomente los archivos que desea eliminar. Luego, ejecute sh remove-duplicate-files.sh . ¡Voila!

ACTUALIZAR

Bueno, si no desea eliminar archivos solo en ciertos directorios, es tan simple como esto :

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 

Donde exclude_duplicates.py es:

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

El remove-duplicate-files-keep-protected.sh archivo que acabamos de crear tendrá todos los archivos de directorios protegidos comentados. Abra este archivo en su editor de texto favorito, verifique que todo esté bien. Luego ejecútelo. ¡Voila (sic)!

Comentarios

  • Pensé en esto, pero ‘ no está lo suficientemente automatizado. Estúpidamente, causé la pérdida de datos con este método cuando lidiando con duplicados espaciados en múltiples sistemas de archivos … no hay ‘ s no hay forma de asignar una prioridad, dada la salida de fdup es. Básicamente, habría tenido que rastrear 10000 archivos a mano para evitar la pérdida de datos … así que no gracias … de hecho, esa pérdida de datos es la razón por la que hice esta pregunta.
  • @ixtmixilix, bueno, el método manual depende de la atención del usuario, aquí ‘ no es nada nuevo. Si desea algo más automatizado, consulte una respuesta actualizada anterior.

Respuesta

¿Qué pasa con algo como esto?

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

Respuesta

A partir de Apple Filesystem (APFS), otra solución es mantener los archivos, deduplicarlos y no tener ningún impacto en el uso del disco. Ver Reemplazar archivos duplicados existentes en APFS con clones

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *