Como remover arquivos duplicados em um diretório?

Como remover arquivos duplicados em um diretório?

Baixei muitas imagens em um diretório.
Downloader renomeou arquivos que já existem.
Também renomeei alguns dos arquivos manualmente.

a.jpg
b.jpg
b(2).jpg
hello.jpg      <-- manually renamed `b(3).jpg`
c.jpg
c(2).jpg
world.jpg      <-- manually renamed `d.jpg`
d(2).jpg
d(3).jpg

Como remover os duplicados? O resultado deve ser:

a.jpg
b.jpg
c.jpg
world.jpg

nota: o nome não importa. Eu só quero arquivos uniq.

Responder1

bash 4.x

#!/bin/bash
declare -A arr
shopt -s globstar

for file in **; do
  [[ -f "$file" ]] || continue
   
  read cksm _ < <(md5sum "$file")
  if ((arr[$cksm]++)); then 
    echo "rm $file"
  fi
done

Isso é recursivo e lida com qualquer nome de arquivo. A desvantagem é que ela requer a versão 4.x para poder usar matrizes associativas e pesquisa recursiva. Remova o echose você gostar dos resultados.

versão boquiaberta

gawk '
  {
    cmd="md5sum " q FILENAME q
    cmd | getline cksm
    close(cmd)
    sub(/ .*$/,"",cksm)
    if(a[cksm]++){
      cmd="echo rm " q FILENAME q
      system(cmd)
      close(cmd)
    }
    nextfile
  }' q='"' *

Observe que isso ainda será interrompido em arquivos que possuem aspas duplas em seus nomes. Não há maneira real de contornar isso com awk. Remova o echose você gostar dos resultados.

Responder2

fdupesé a ferramenta de sua escolha. Para localizar todos os arquivos duplicados (por conteúdo, não por nome) no diretório atual:

fdupes -r .

Para confirmar manualmente a exclusão de arquivos duplicados:

fdupes -r -d .

Para excluir automaticamente todas as cópias, exceto a primeira de cada arquivo duplicado (esteja avisado, este aviso, isso realmente exclui arquivos, conforme solicitado):

fdupes -r -f . | grep -v '^$' | xargs rm -v

Eu recomendo verificar manualmente os arquivos antes de excluí-los:

fdupes -rf . | grep -v '^$' > files
... # check files
xargs -a files rm -v

Responder3

Eu recomendoclones.

Fclones é um moderno localizador e removedor de arquivos duplicados escrito em Rust, disponível na maioria das distribuições Linux e macOS.

Recursos notáveis:

  • suporta espaços, caracteres não-ASCII e de controle em caminhos de arquivo
  • permite pesquisar em múltiplas árvores de diretórios
  • respeita arquivos .gitignore
  • seguro: permite inspecionar a lista de duplicatas manualmente antes de realizar qualquer ação sobre elas
  • oferece muitas opções para filtrar/selecionar arquivos para remover ou preservar
  • muito rápido

Para procurar duplicatas no diretório atual, basta executar:

fclones group . >dupes.txt

Em seguida, você pode inspecionar o dupes.txtarquivo para verificar se encontrou as duplicatas corretas (você também pode modificar essa lista ao seu gosto).

Por fim, remova/vincule/mova os arquivos duplicados com um dos seguintes:

fclones remove <dupes.txt
fclones link <dupes.txt
fclones move target <dupes.txt
fclones dedupe <dupes.txt   # copy-on-write deduplication on some filesystems

Exemplo:

pkolaczk@p5520:~/Temp$ mkdir files
pkolaczk@p5520:~/Temp$ echo foo >files/foo1.txt
pkolaczk@p5520:~/Temp$ echo foo >files/foo2.txt
pkolaczk@p5520:~/Temp$ echo foo >files/foo3.txt

pkolaczk@p5520:~/Temp$ fclones group files >dupes.txt
[2022-05-13 18:48:25.608] fclones:  info: Started grouping
[2022-05-13 18:48:25.613] fclones:  info: Scanned 4 file entries
[2022-05-13 18:48:25.613] fclones:  info: Found 3 (12 B) files matching selection criteria
[2022-05-13 18:48:25.614] fclones:  info: Found 2 (8 B) candidates after grouping by size
[2022-05-13 18:48:25.614] fclones:  info: Found 2 (8 B) candidates after grouping by paths and file identifiers
[2022-05-13 18:48:25.619] fclones:  info: Found 2 (8 B) candidates after grouping by prefix
[2022-05-13 18:48:25.620] fclones:  info: Found 2 (8 B) candidates after grouping by suffix
[2022-05-13 18:48:25.620] fclones:  info: Found 2 (8 B) redundant files

pkolaczk@p5520:~/Temp$ cat dupes.txt
# Report by fclones 0.24.0
# Timestamp: 2022-05-13 18:48:25.621 +0200
# Command: fclones group files
# Base dir: /home/pkolaczk/Temp
# Total: 12 B (12 B) in 3 files in 1 groups
# Redundant: 8 B (8 B) in 2 files
# Missing: 0 B (0 B) in 0 files
6109f093b3fd5eb1060989c990d1226f, 4 B (4 B) * 3:
    /home/pkolaczk/Temp/files/foo1.txt
    /home/pkolaczk/Temp/files/foo2.txt
    /home/pkolaczk/Temp/files/foo3.txt

pkolaczk@p5520:~/Temp$ fclones remove <dupes.txt
[2022-05-13 18:48:41.002] fclones:  info: Started deduplicating
[2022-05-13 18:48:41.003] fclones:  info: Processed 2 files and reclaimed 8 B space

pkolaczk@p5520:~/Temp$ ls files
foo1.txt

Responder4

Como testar arquivos com conteúdo exclusivo?

if diff "$file1" "$file2" > /dev/null; then
    ...

Como podemos obter uma lista de arquivos no diretório?

files="$( find ${files_dir} -type f )"

Podemos obter 2 arquivos quaisquer dessa lista e verificar se seus nomes são diferentes e o conteúdo é o mesmo.

#!/bin/bash
# removeDuplicates.sh

files_dir=$1
if [[ -z "$files_dir" ]]; then
    echo "Error: files dir is undefined"
fi

files="$( find ${files_dir} -type f )"
for file1 in $files; do
    for file2 in $files; do
        # echo "checking $file1 and $file2"
        if [[ "$file1" != "$file2" && -e "$file1" && -e "$file2" ]]; then
            if diff "$file1" "$file2" > /dev/null; then
                echo "$file1 and $file2 are duplicates"
                rm -v "$file2"
            fi
        fi
    done
done

Por exemplo, temos algum diretório:

$> ls .tmp -1
all(2).txt
all.txt
file
text
text(2)

Portanto, existem apenas 3 arquivos exclusivos.

Vamos executar esse script:

$> ./removeDuplicates.sh .tmp/
.tmp/text(2) and .tmp/text are duplicates
removed `.tmp/text'
.tmp/all.txt and .tmp/all(2).txt are duplicates
removed `.tmp/all(2).txt'

E temos apenas 3 arquivos restantes.

$> ls .tmp/ -1
all.txt
file
text(2)

informação relacionada