Tengo un directorio con varios archivos img y algunos de ellos son idénticos, pero todos tienen nombres diferentes. Necesito eliminar duplicados pero sin herramientas externas solo con un bash
script. Soy un principiante en Linux. Intenté anidar para el bucle para comparar md5
sumas y, dependiendo del resultado, eliminar, pero algo está mal con la sintaxis y no funciona. ¿alguna ayuda?
lo que he intentado es ...
for i in directory_path; do
sum1='find $i -type f -iname "*.jpg" -exec md5sum '{}' \;'
for j in directory_path; do
sum2='find $j -type f -iname "*.jpg" -exec md5sum '{}' \;'
if test $sum1=$sum2 ; then rm $j ; fi
done
done
Yo obtengo: test: too many arguments
bash
shell-script
linuxbegin
fuente
fuente
Respuestas:
Hay bastantes problemas en su script.
En primer lugar, con el fin de asignar el resultado de un comando a una variable que necesita para encerrarlo ya sea en backtics (
`command`
) o, preferiblemente,$(command)
. Lo tiene entre comillas simples ('command'
) que, en lugar de asignar el resultado de su comando a su variable, asigna el comando en sí como una cadena. Por lo tanto, tutest
es en realidad:El siguiente problema es que el comando
md5sum
devuelve más que solo el hash:Solo desea comparar el primer campo, por lo que debe analizar el
md5sum
resultado pasándolo a través de un comando que solo imprime el primer campo:o
Además, el
find
comando devolverá muchas coincidencias, no solo una y cada una de esas coincidencias se duplicará por la segundafind
. Esto significa que en algún momento comparará el mismo archivo consigo mismo, el md5sum será idéntico y terminará eliminando todos sus archivos (ejecuté esto en un directorio de prueba que contienea.jpg
yb.jpg
):No desea ejecutar a
for i in directory_path
menos que esté pasando una serie de directorios. Si todos estos archivos están en el mismo directorio, desea ejecutarfor i in $(find directory_path -iname "*.jpg"
) para revisar todos los archivos.Es una mala idea usar
for
bucles con la salida de find. Debe usarwhile
bucles o globbing :o, si todos sus archivos están en el mismo directorio:
Dependiendo de su shell y las opciones que haya configurado, puede usar globbing incluso para archivos en subdirectorios, pero no entremos en eso aquí.
Finalmente, también debe citar sus variables; de lo contrario, las rutas de directorio con espacios romperán su script.
Los nombres de archivo pueden contener espacios, nuevas líneas, barras invertidas y otros caracteres extraños, para tratarlos correctamente en un
while
bucle necesitará agregar algunas opciones más. Lo que quieres escribir es algo como:Una forma aún más simple sería:
Una mejor versión que puede manejar espacios en los nombres de archivo:
Este pequeño script de Perl se ejecutará a través de los resultados del
find
comando (es decir, el md5sum y el nombre del archivo). La-a
opción paraperl
dividir líneas de entrada en espacios en blanco y guardarlas en laF
matriz,$F[0]
será md5sum y$F[1]
el nombre del archivo. El md5sum se guarda en el hashk
y el script comprueba si el hash ya se ha visto (if $k{$F[0]}>1
) y elimina el archivo si lo tiene (system("rm $F[1]")
).Si bien eso funcionará, será muy lento para grandes colecciones de imágenes y no puede elegir qué archivos guardar. Hay muchos programas que manejan esto de una manera más elegante, incluyendo:
fdupes
fslint
fuente
unlink
lugar de hacer unasystem
llamada.$F[1]
. Se solucionó utilizando rebanadas de matriz. En cuanto a unlink (), lo sé, pero quería mantener los perlismos al mínimo y la llamada al sistema es más fácil de entender si no conoce a Perl.Hay un programa ingenioso llamado
fdupes
que simplifica todo el proceso y solicita al usuario que elimine los duplicados. Creo que vale la pena verificarlo:Básicamente, me solicitó qué archivo guardar , escribí 1 y eliminó el segundo.
Otras opciones interesantes son:
A partir de su ejemplo, probablemente quiera ejecutarlo como:
Ver
man fdupes
para todas las opciones disponibles.fuente