Existem alguns problemas no seu script.
-
Primeiro, para atribuir o resultado de um comando a uma variável, é necessário incluí-lo no backtics (
'command') ou, preferencialmente,$(command). Você tem isso entre aspas simples ('command'), que ao invés de atribuir o resultado do seu comando à sua variável, atribui o próprio comando como uma string. Portanto, seutesté, na verdade:$ echo "test $sum1=$sum2" test find $i -type f -iname "*.jpg" -exec md5sum {} \;=find $j -type f -iname "*.jpg" -exec md5sum {} \; -
A próxima questão é que o comando
md5sumretorna mais do que apenas o hash:$ md5sum /etc/fstab 46f065563c9e88143fa6fb4d3e42a252 /etc/fstabVocê só deseja comparar o primeiro campo, portanto, deve analisar o
md5sumoutput passando-o por um comando que imprime apenas o primeiro campo:find $i -type f -iname "*.png" -exec md5sum '{}' \; | cut -f 1 -d ' 'ou
find $i -type f -iname "*.png" -exec md5sum '{}' \; | awk '{print $1}' -
Além disso, o comando
findretornará muitas correspondências, não apenas uma e cada uma dessas correspondências será duplicada pela segundafind. Isso significa que em algum momento você estará comparando o mesmo arquivo a si mesmo, o md5sum será idêntico e você acabará excluindo todos seus arquivos (executei isso em um diretório de teste contendoa.jpgeb.jpg):for i in $(find . -iname "*.jpg"); do for j in $(find . -iname "*.jpg"); do echo "i is: $i and j is: $j" done done i is: ./a.jpg and j is: ./a.jpg ## BAD, will delete a.jpg i is: ./a.jpg and j is: ./b.jpg i is: ./b.jpg and j is: ./a.jpg i is: ./b.jpg and j is: ./b.jpg ## BAD will delete b.jpg -
Você não deseja executar
for i in directory_path, a menos que esteja passando uma matriz de diretórios. Se todos esses arquivos estiverem no mesmo diretório, você deseja executarfor i in $(find directory_path -iname "*.jpg") para percorrer todos os arquivos. -
É uma má idéia de usar
forloops com a saída de encontrar. Você deve usarwhileloops ou globbing :find . -iname "*.jpg" | while read i; do [...] ; doneou, se todos os seus arquivos estiverem no mesmo diretório:
for i in *jpg; do [...]; doneDependendo do seu shell e das opções que você definiu, você pode usar globbing até para arquivos em subdiretórios, mas não vamos entrar aqui.
-
Finalmente, você também deve citar suas variáveis, senão os caminhos de diretório com espaços irão quebrar seu script.
Os nomes dos arquivos podem conter espaços, novas linhas, barras invertidas e outros caracteres estranhos, para lidar com eles corretamente em um loop while , você precisará adicionar mais algumas opções. O que você quer escrever é algo como:
find dir_path -type f -iname "*.jpg" -print0 | while IFS= read -r -d '' i; do
find dir_path -type f -iname "*.jpg" -print0 | while IFS= read -r -d '' j; do
if [ "$i" != "$j" ]
then
sum1=$(md5sum "$i" | cut -f 1 -d ' ' )
sum2=$(md5sum "$j" | cut -f 1 -d ' ' )
[ "$sum1" = "$sum2" ] && rm "$j"
fi
done
done
Uma maneira ainda mais simples seria:
find directory_path -name "*.jpg" -exec md5sum '{}' + |
perl -ane '$k{$F[0]}++; system("rm $F[1]") if $k{$F[0]}>1'
Uma versão melhor que pode lidar com espaços em nomes de arquivos:
find directory_path -name "*.jpg" -exec md5sum '{}' + |
perl -ane '$k{$F[0]}++; system("rm \"@F[1 .. $#F]\"") if $k{$F[0]}>1'
Esse pequeno script Perl será executado pelos resultados do comando find (ou seja, o md5sum e o nome do arquivo). A opção -a para perl divide as linhas de entrada no espaço em branco e as salva na matriz F , portanto $F[0] será o md5sum e $F[1] o nome do arquivo. O md5sum é salvo no hash k e o script verifica se o hash já foi visto ( if $k{$F[0]}>1 ) e exclui o arquivo se tiver ( system("rm $F[1]") ).
Enquanto isso vai funcionar, será muito lento para grandes coleções de imagens e você não pode escolher quais arquivos manter. Existem muitos programas que lidam com isso de uma maneira mais elegante, incluindo: