Como remover arquivos duplicados usando o bash

10

Eu tenho uma pasta com arquivos duplicados (por md5sum( md5em um Mac)) e quero ter um trabalho agendado para remover qualquer encontrado.

No entanto, eu estou preso em como fazer isso. O que tenho até agora:

md5 -r * | sort

Que gera algo como isto:

04c5d52b7acdfbecd5f3bdd8a39bf8fb gordondam_en-au11915031300_1366x768.jpg
1e88c6899920d2c192897c886e764fc2 fortbourtange_zh-cn9788197909_1366x768.jpg
266ea304b15bf4a5650f95cf385b16de nebraskasupercell_fr-fr11286079811_1366x768.jpg
324735b755c40d332213899fa545c463 grossescheidegg_en-us10868142387_1366x768.jpg
3993028fcea692328e097de50b26f540 Soyuz Spacecraft Rolled Out For Launch of One Year Crew.png
677bcd6006a305f4601bfb27699403b0 lechaustria_zh-cn7190263094_1366x768.jpg
80d03451b88ec29bff7d48f292a25ce6 ontariosunrise_en-ca10284703762_1366x768.jpg
b6d9d24531bc62d2a26244d24624c4b1 manateeday_row10617199289_1366x768.jpg
ca1486dbdb31ef6af83e5a40809ec561 Grueling Coursework.jpg
cdf26393577ac2a61b6ce85d22daed24 Star trails over Mauna Kea.jpg
dc3ad6658d8f8155c74054991910f39c smoocave_en-au10358472670_1366x768.jpg
dc3ad6658d8f8155c74054991910f39c smoocave_en-au10358472670_1366x7682.jpg

Como processar com base no MD5 do arquivo para remover duplicatas? Eu realmente não me importo com qual "original" eu mantenho - mas eu só quero manter uma.

Devo abordar isso de uma maneira diferente?

Warren
fonte
3
Já existe um fdupescomando que fará isso ... Não tenho certeza em qual distro você está, mas está em um pacote Debian com o mesmo nome. Além disso, o MD5 é um hash bastante fraco atualmente; você provavelmente vai querer usar sha256sum ou melhor sha512sum(que deve realmente ser mais rápido em hardware de PC normal)
derobert
1
@derobert - Eu sei MD5 é um hash fraco, mas é o suficiente simples e bom para a comparação de arquivos pequenos :)
Warren
bem, as colisões MD5 são conhecidas e geráveis ​​com quantidades bastante modestas de energia da CPU, e há um comando que você pode substituir para usar o SHA-512, então ...
derobert 26/15/15
@derobert - Eu compreendo que há potenciais negativos para usando md5 .. mas é mais do que adequado neste cenário (que desejam para garantir que eu não tenho arquivos duplicados em um determinado diretório)
Warren
1
Justo. O ponto principal do comentário foi apontar fdupes.
26415 derobert

Respostas:

3

Estou trabalhando no Linux, o que significa que é o comando md5sumque gera:

> md5sum *
d41d8cd98f00b204e9800998ecf8427e  file_1
d41d8cd98f00b204e9800998ecf8427e  file_10
d41d8cd98f00b204e9800998ecf8427e  file_2
d41d8cd98f00b204e9800998ecf8427e  file_3
d41d8cd98f00b204e9800998ecf8427e  file_4
d41d8cd98f00b204e9800998ecf8427e  file_5
d41d8cd98f00b204e9800998ecf8427e  file_6
d41d8cd98f00b204e9800998ecf8427e  file_7
d41d8cd98f00b204e9800998ecf8427e  file_8
d41d8cd98f00b204e9800998ecf8427e  file_9
b026324c6904b2a9cb4b88d6d61c81d1  other_file_1
31d30eea8d0968d6458e0ad0027c9f80  other_file_10
26ab0db90d72e28ad0ba1e22ee510510  other_file_2
6d7fce9fee471194aa8b5b6e47267f03  other_file_3
48a24b70a0b376535542b996af517398  other_file_4
1dcca23355272056f04fe8bf20edfce0  other_file_5
9ae0ea9e3c9c6e1b9b6252c8395efdc1  other_file_6
84bc3da1b3e33a18e8d5e1bdd7a18d7a  other_file_7
c30f7472766d25af1dc80b3ffc9a58c7  other_file_8
7c5aba41f53293b712fd86d08ed5b36e  other_file_9

Agora, usando awke xargso comando seria:

md5sum * | \
sort | \
awk 'BEGIN{lasthash = ""} $1 == lasthash {print $2} {lasthash = $1}' | \
xargs rm

A awkpeça é inicializada lasthashcom a sequência vazia, que não corresponde a nenhum hash e, em seguida, verifica cada linha se o hash in lasthashfor igual ao hash (primeira coluna) do arquivo atual (segunda coluna). Se for, imprime. No final de cada etapa, ele será definido lasthashcomo o hash do arquivo atual (você pode limitar isso para ser definido apenas se os hashes forem diferentes, mas isso deve ser uma coisa menor, especialmente se você não tiver muitos arquivos correspondentes). Os nomes de arquivos que awk cospe são alimentados rmcom xargs, o que basicamente chama rmcom o que a awkparte nos fornece.

Você provavelmente precisará filtrar diretórios antes md5sum *.

Editar:

Usando o método Marcins, você também pode usar este:

comm -1 -2 \
  <(ls) | \
  <(md5sum * | \
    sort -k1 | \
    uniq -w 32 | \
    awk '{print $2}' | \
    sort) \
xargs rm

Esse substrato da lista de arquivos obtida pelo lsprimeiro nome do arquivo de cada hash exclusivo obtido por md5sum * | sort -k1 | uniq -w 32 | awk '{print $2}'.

Tristan Storch
fonte
1
graças: md5 -r * | sort -t ' ' -k 4 -r | awk 'BEGIN{lasthash = ""} $1 == lasthash {print $2} {lasthash = $1}' | xargs rmé a chamada em OS X (por @ Stephen Kitt sugestão 's, eu pôr echo 'will remove 'no final antes de tentar isso com rm)
Warren
Provavelmente você deve editar sua pergunta porque a solução fornecida não corresponde ao exemplo de saída que você forneceu.
Stephen Kitt
1
E você deve mudar sort -t ' ' -k 4 -rpara sort.
Tristan Storch
@TristanStorch - good spot :)
warren
Isso pressupõe que você não tem espaços em seus nomes de arquivo, uma suposição perigosa em qualquer circunstância. (E especialmente dado o OP está usando um Mac Eu te desafio a encontrar um Mac, qualquer Mac, que não tem nomes de arquivos contendo espaço em tudo..) :)
Wildcard
7

Você pode identificar arquivos duplicados usando o seguinte comando:

md5sum * | sort -k1 | uniq -w 32 -d
Marcin
fonte
1
Isso gera apenas um arquivo para cada conjunto de duplicatas. Se você deseja excluir todas as duplicatas e manter apenas uma, pode manter as que obtiver com este comando e excluir o restante
golimar
2

Encontrei fdupes como resposta a essa pergunta semelhante: /superuser/386199/how-to-remove-duplicated-files-in-a-directory

Eu era capaz apt-get install fdupesno Ubuntu. Você definitivamente vai querer ler a página de manual. No meu caso, consegui os resultados desejados da seguinte forma:

fdupes -qdN -r /ops/backup/

O que diz "examine recursivamente o arquivo / ops / backup e encontre todos os arquivos duplicados: mantenha a primeira cópia de qualquer arquivo e remova o restante silenciosamente". Isso facilita muito a manutenção de vários despejos de um banco de dados de gravação infreqüente.

dannyman
fonte
1

Se você estiver com pressa (ou tiver muitos arquivos) e quiser evitar uma sobrecarga de uma espécie (leva tempo), mas não se importe com a sobrecarga de memória de uma tabela de hash (ou você tem bastante memória RAM com seus lotes) de arquivos),

find . -type f -print0 | xargs -0 md5sum | awk 'h[$1]{ printf "%s\0", $2; next }{ h[$1] = $2 }' | xargs -0 rm

find . -type f -print0: Encontre todos os arquivos e produza-os com nomes terminados em nulo

xargs -0 md5sum: calcule hashes em paralelo (ajuste -nmax-args e -Pmax-procs conforme desejado, consulte man xargs)

awk 'h[$1]{ printf "%s\0", $2; next }{ h[$1] = $2 }': se houver uma entrada na hashtable awk que contenha o md5sum que estamos vendo no momento, imprima o nome do arquivo que estamos vendo no momento, terminado por nulo. Caso contrário, adicione o nome do arquivo à tabela de hash.

xargs -0 rm: pegue as seqüências terminadas em nulo e envie-as para rm.

Isso é muito mais rápido que o fdupes.

Se você tiver um nome de arquivo que contenha uma nova linha, o awk provavelmente o truncará na nova linha, pois o md5sum também separa registros por novas linhas.

Isso é baseado em /programming/11532157/remove-duplicate-lines-without-sorting e /programming/9133315/how-can-i-output-null-terminated- cordas-em-awk

Alex
fonte
1
md5sum * | sort -k1 | uniq -w 32 -d | cut -d' ' -f3 | xargs -I{} sh -c 'rm {}'
  1. pegue todos os valores md5
  2. classificá-los para que os enganados sejam sequenciais para o uniq
  3. execute o uniq para gerar apenas dupes
  4. corte o nome do arquivo da linha com o valor md5
  5. chamar repetidamente delete nos nomes de arquivos
Carter Cole
fonte
0
comm -13 <(md5sum * | sort | uniq -w 32 -d) <(md5sum * | sort | uniq -w 32 -D) | cut -f 3- -d" " | xargs -d '\n' rm

Recursos:

  • Ainda funciona se houver mais de uma duplicata por arquivo
  • Ainda funciona se os nomes de arquivos tiverem espaços
  • Ainda funciona se você tiver um alias lscom uma classificação ou--color=always
Alex Lamson
fonte