Eu tenho um diretório com vários arquivos img e alguns deles são idênticos, mas todos têm nomes diferentes. Preciso remover duplicatas, mas sem ferramentas externas, apenas com um bash
script. Eu sou iniciante no Linux. Eu tentei aninhado para loop para comparar md5
somas e, dependendo do resultado remover, mas algo está errado com a sintaxe e não funciona. qualquer ajuda?
o que eu tentei é ...
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
Eu recebo: test: too many arguments
bash
shell-script
linuxbegin
fonte
fonte
Respostas:
Existem alguns problemas no seu script.
Primeiro, para atribuir o resultado de um comando a uma variável, você deve incluí-lo em backtics (
`command`
) ou, preferencialmente$(command)
,. Você o coloca entre aspas simples ('command'
) que, em vez de atribuir o resultado do seu comando à sua variável, atribui o próprio comando como uma string. Portanto, vocêtest
é realmente:O próximo problema é que o comando
md5sum
retorna mais do que apenas o hash:Você deseja comparar apenas o primeiro campo, portanto, deve analisar a
md5sum
saída passando-a por um comando que imprime apenas o primeiro campo:ou
Além disso, o
find
comando retornará muitas correspondências, não apenas uma e cada uma dessas correspondências será duplicada a cada segundofind
. Isso significa que em algum momento você estará comparando o mesmo arquivo, o md5sum será idêntico e você acabará excluindo todos os seus arquivos (eu executei isso em um diretório de teste contendoa.jpg
eb.jpg
):Você não deseja executar, a
for i in directory_path
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 passar por todos os arquivos.É uma má idéia usar
for
loops com a saída do find. Você deve usarwhile
loops ou globbing :ou, se todos os seus arquivos estiverem no mesmo diretório:
Dependendo do seu shell e das opções que você definiu, você pode usar globbing mesmo para arquivos em subdiretórios, mas não vamos entrar aqui.
Por fim, você também deve citar suas variáveis, caso contrário, os caminhos de diretório com espaços quebrarão seu script.
Os nomes de arquivos podem conter espaços, novas linhas, barras invertidas e outros caracteres estranhos. Para lidar com aqueles corretamente em um
while
loop, você precisará adicionar mais algumas opções. O que você deseja escrever é algo como:Uma maneira ainda mais simples seria:
Uma versão melhor que pode lidar com espaços nos nomes dos arquivos:
Este pequeno script Perl executará os resultados do
find
comando (ou seja, o md5sum e o nome do arquivo). A-a
opção paraperl
dividir as linhas de entrada no espaço em branco e salvá-las naF
matriz, assim$F[0]
será o md5sum e$F[1]
o nome do arquivo. O md5sum é salvo no hashk
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]")
).Embora isso funcione, será muito lento para grandes coleções de imagens e você não poderá escolher quais arquivos manter. Existem muitos programas que lidam com isso de uma maneira mais elegante, incluindo:
fdupes
fslint
fonte
unlink
vez de fazer umasystem
chamada.$F[1]
. Corrigido usando fatias de matriz. Quanto a unlink () eu sei, mas queria manter os perlismos no mínimo e a chamada do sistema é mais fácil de entender se você não conhece o Perl.Existe um programa bacana chamado
fdupes
que simplifica todo o processo e solicita ao usuário a exclusão de duplicatas. Eu acho que vale a pena conferir:Basicamente, ele me solicitou qual arquivo manter , digitei 1 e removi o segundo.
Outras opções interessantes são:
Do seu exemplo, você provavelmente deseja executá-lo como:
Veja
man fdupes
para todas as opções disponíveis.fonte