¿Existe alguna forma de eliminar duplicados más refinada que fdupes -rdN?

¿Existe alguna forma de eliminar duplicados más refinada que fdupes -rdN?

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 fdupesparecía que era la mejor herramienta para el trabajo, pero cada vez me encuentro con limitaciones.

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

Y cuando encuentra duplicados, los elimina, de modo que solo queda una copia de todo.

Pero, ¿qué pasa si quiero conservarlo somedirectory/subdirectory1/somefiley, de hecho, hay cuatro duplicados y el programa encuentra primero uno de los duplicados? Luego elimina somedirectory/subdirectory1/somefile, lo cual no quiero.

Quiero poder especificar, de alguna manera, qué duplicados conservar. Y hasta ahora, ninguno de los programas estándar para tratar duplicados (duff, FSLint) parece permitir la automatización de ese tipo de comportamiento. Preferiría no rodar el mío, por eso hago esta pregunta.

Me gustaría poder escribir algo como

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

Respuesta1

Si bien la funcionalidad que buscas no está disponible en stock fdupes, bifurquéfdupes (mi tenedor se llama jdupes)y agregó algunas características que pueden resolver este problema bajo ciertas circunstancias. Por ejemplo, en el caso indicado en el que desea conservar somedirectory/subdirectory1/somefilecuando se eliminan automáticamente los duplicados ( dy Ncambia juntos) y no hay archivos separados inmediatamente debajo somedirectory, jdupespuede alimentar cada ruta de subdirectorio inmediato con subdirectory1primero y el -Ointerruptor (que ordena los archivos por comando -orden de parámetros de línea primero):

jdupes -rdNO somedirectory/subdirectory1 somedirectory/subdirectory2 somedirectory/subdirectory3

Esto eliminará automáticamente todos los archivos menos uno en un conjunto duplicado y garantizará que, si el conjunto contiene un archivo, somedirectory/subdirectory1será el primero, convirtiéndose automáticamente en el archivo conservado del conjunto. Todavía existen límites evidentes para este enfoque, como el hecho de que somedirectory/subdirectory1se podría conservar otro duplicado en lugar del que desea conservar, pero en un buen número de casos como el suyo, la jdupesopción de orden de parámetros como solución alternativa es suficientemente buena.

En un futuro cercano, planeo agregar un sistema de filtrado jdupesque permitirá una gran cantidad de control sobre la inclusión/exclusión de archivos, la preservación de -Nacciones y la aplicación de dichas "pilas de filtros" ya sea de forma global o por parámetro. Esta característica es muy necesaria; Me imagino algo como esto para "eliminar automáticamente duplicados distintos de cero de forma recursiva PERO conservar siempre somedirectory/subdirectory1/somefilecomo está":

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

ACTUALIZACIÓN (2022-03-01):Eche un vistazo a las -Xopciones de filtro extendidas agregadas en 2020. No es exactamente lo que desea, pero los filtros nostry onlystrle permiten especificar subcadenas dentro de una ruta completa para ignorarlas o requerirlas.

Respuesta2

No vi este en ningún otro lugar: Di lo que quieras 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 la misma 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 sola 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

Respuesta3

¿Qué pasa si vinculamos los archivos duplicados? De esa forma el espacio solo se usa una vez, pero aún existen en todos los caminos. El problema con esto es que los archivos vinculados 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 podría hacer con el siguiente script (aunque tenga en cuenta que esto no maneja nombres de archivos que contengan espacios).

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

Respuesta4

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

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

Nuevamente, 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 desee conservar.

Otro consejo para directorios grandes es ejecutar fdupes en un archivo txt, luego experimentar con | grepy | sedhasta obtener el resultado que deseo.

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

información relacionada