Eliminación por lotes de archivos más pequeños del grupo de archivos a través de la línea de comandos de Unix

3

Tengo una gran cantidad (más de 400) de directorios llenos de fotos. Lo que quiero hacer es mantener los tamaños más grandes de estas fotos. Cada directorio tiene de 31 a 66 archivos.

Cada directorio tiene miniaturas y versiones más grandes, además de un archivo llamado example.jpg

Envié el archivo example.jpg fácilmente con:

rm */example.jpg

Inicialmente pensé que sería fácil eliminar las miniaturas, pero el problema es que no tienen nombres consistentes. El patrón típico era photo1.jpgy photo1s.jpg. Lo hice, rm */photo*s.jpgpero terminó porque algunos de los archivos nombrados photoXs.jpgeran en realidad más grandes y no más pequeños. Argh

Entonces, lo que quiero hacer es escanear cada directorio en busca de tamaño de archivo y eliminar (o mover) las miniaturas. Inicialmente pensé que simplemente ls -Rcada archivo y extraer el tamaño de cada archivo y guardarlos por debajo de un umbral. ¿El problema? En un directorio, el tamaño grande será de 1.1 MB y el pulgar es de 200k. En otro, el grande es de 200k y el pequeño de 30k.

Peor aún, los archivos realmente se nombran principalmente photo1.jpg, por lo que simplemente ponerlos todos en la misma carpeta, ordenarlos por tamaño y eliminarlos en grupos ya no funcionaría sin renombrarlos, y si es posible, preferiría mantenerlos en sus carpetas.

Casi estaba decidido a hacer todo esto manualmente, pero luego pensé en preguntar aquí.

¿Cómo harías esta tarea?

artlung
fuente
¿Existe alguna relación entre el nombre de una imagen y su imagen en miniatura u otras imágenes de tamaño?
Marnix A. van Ammers

Respuestas:

1

Este script supone que hay una brecha significativa en los tamaños entre los grupos de archivos más pequeños y más grandes. En particular, el más pequeño de los archivos grandes es al menos dos veces más grande que el más grande de los archivos pequeños.

Llame al script "imagedirstats" y ejecútelo en un bucle como este:

find /path/to/main/branch -type d | while read subdir; do (cd "$subdir" && ~/bin/imagedirstats ); done

para encontrar y eliminar archivos en directorios individuales en el árbol de directorios.

Aquí está el guión:

#!/bin/bash
# from http://superuser.com/questions/135951/batch-deletion-of-smaller-files-from-group-of-files-via-unix-command-line
# by Dennis Williamson - 2010-04-29

prevn=1     # prevent division by zero
factor=4    # how close to the largest of the small files to set the threshold, 4 == one fourth of the way above
min=1000    # ignore files below this size

while read n
do
    (( ratio = n / prevn ))
    if (( ratio > 1 && n > min ))
    then
        break
    fi
    if (( n > 0 ))
    then
        prevn=$n
    fi
done < <(find . -maxdepth 1 -name "*.jpg" -printf "%s\n" | sort -n)
# for OS X, comment out the preceding line and uncomment this one:
# done < <(find . -maxdepth 1 -name "*.jpg" | stat -f "%z" | sort -n)

# the following line would be the GNU equivalent using stat(1) instead of printf
# it's included here for reference:
# done < <(find . -maxdepth 1 -name "*.jpg" | stat -c "%s" | sort -n)

(( size = (n - prevn) / factor + prevn ))

echo "Smallest of the large: $n"
echo "Largest of the small: $prevn"
echo "Ratio: $ratio"
echo "Threshold: $size"

if (( ratio < 2 ))
then
    read -p "Warning: ratio too small. Delete anyway? Only 'Yes' will proceed" reply
    if [[ $reply != "Yes" ]]
    then
        echo "Cancelled" >&2
        exit 1
    fi
fi

# uncomment the delete on the following line to actually do the deletion

find . -maxdepth 1 -name "*.jpg" -size -${size}c # -delete

Editar: movió el aviso de advertencia para que primero se muestre información útil. Se corrigió una falta fi.

Edición 2: hizo que los dos findcomandos sean consistentes. Se agregó una variación comentada para OS X. Se agregó información sobre cómo ejecutar el script.

Dennis Williamson
fuente
Lo guardé como imagedirstats:y lo ejecuté ~/bin/imagedirstats */*y el resultado es: -bash: /Users/artlung/bin/imagedirstats: Argument list too long... ~/bin/imagedirstats *find: illegal option -- p find: illegal option -- r find: illegal option -- i find: illegal option -- n find: illegal option -- t find: %s\n: No such file or directory /Users/artlung/bin/imagedirstats: line 38: syntax error: unexpected end of file
ejecuté
El guión no toma ningún argumento. Está diseñado para ejecutarse en el directorio actual o dentro de un ciclo que itera sobre un conjunto de directorios. Además, vea dónde edité el findcomando. Olvidé incluir una -maxdepthdiscusión.
Dennis Williamson
¿Qué find --versionte da? ¿Qué distribución de Linux (y versión)?
Dennis Williamson
La razón de las restricciones current-directory y maxdepth es para acomodar la condición que describió en su pregunta en la que los rangos de tamaño de archivo se superponen en los directorios.
Dennis Williamson
Así es como podría verse el bucle externo:find /path/to/main/branch -type d | while read subdir; do (cd "$subdir" && ~/bin/imagedirstats ); done
Dennis Williamson
4

Si puede encontrar un límite específico, por ejemplo, todas las imágenes grandes son mayores de 200 KB, entonces puede hacer esto:

find */*.jpg -size -200k -delete

Es posible que desee hacer una copia de seguridad primero.

Chris S
fuente
Esto es prometedor Desafortunadamente, no hay un límite claro en el tamaño, pero esta es una buena manera de reducir la mayoría. ¡Gracias!
artlung
3

Si los tamaños de archivo no son consistentes, ¿son las dimensiones de la imagen?

Podría usar identify, una herramienta que viene con ImageMagick, para tomar las dimensiones de la imagen. A través de algunas secuencias de comandos bash simples, puede trabajar con las imágenes según su tamaño.

Para capturar el ancho y el alto de una imagen con identify:

identificar el nombre de archivo -format '% wx% h'

obtendrá la salida de esta manera:

[John @ impresionante: ~] $ Identificar -formato '% wx% h' W4.JPG
1680x1050

Luego puede usar la cututilidad para obtener los números en su script:

[juan @ impresionante: ~] $ identificar -formato '% wx% h' W4.JPG | cortar -d'x '-f1
1680
[juan @ impresionante: ~] $ identificar -formato '% wx% h' W4.JPG | cortar -d'x '-f2
1050
John T
fuente
De acuerdo, instalando imagemagick a través de brew (en Mac) y echaremos un vistazo. Esta es una pieza para extraer altura. Creo que hay cierta consistencia en las alturas de las miniaturas, no en las más grandes. ¡Prometedor!
artlung
Incluso si no son exactamente consistentes, si todas las miniaturas tienen menos de 200 píxeles de altura, puede hacerloif [ $h -lt 200 ] ...
John T
0

Si desea hacer esto en función del nombre del archivo, intente lo siguiente:

find -name '*.jpg' | sed -ne 's:^\(.*\)\.jpg:\1s.jpg$:p' | xargs rm

Encontrará cada archivo .jpg, colocará una "s" al final del nombre de archivo (justo antes de ".") Y lo eliminará.

Petersohn
fuente
1
El OP dijo que los archivos tienen un nombre inconsistente y algunos de los archivos grandes tienen "s".
Dennis Williamson
Gracias petersohn, pero DW tiene razón. Si fueron nombrados como una persona cuerda los nombraría, entonces sería mucho más fácil simplemente eliminar archivos que coincidan con el patrón y listo.
artlung