Como remover arquivos duplicados em um diretório?

24

Eu baixei muitas imagens em um diretório.
O Downloader renomeou arquivos que já existem.
Eu também renomeiei 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.

    
por kev 05.02.2012 / 11:39

11 respostas

20

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 é tanto recursivo quanto manipula qualquer nome de arquivo. A desvantagem é que ele requer a versão 4.x para a capacidade de usar matrizes associativas e pesquisa recursiva. Remova o echo se você gostar dos resultados.

versão do gawk

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 nos arquivos que possuem aspas duplas em seus nomes. Nenhuma maneira real de contornar isso com awk . Remova o echo se você gostar dos resultados.

    
por 05.02.2012 / 12:25
38

fdupes é a ferramenta de sua escolha. Para encontrar 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, mas a primeira de cada arquivo duplicado ( ser avisado, este aviso, isso na verdade exclui arquivos, conforme solicitado ):

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

Eu recomendaria verificar manualmente os arquivos antes da exclusão:

fdupes -rf . | grep -v '^$' > files
... # check files
xargs -a files rm -v
    
por 21.12.2013 / 15:44
2

Você pode experimentar o FSLint . Ele tem tanto a linha de comando e a interface GUI .

    
por 05.02.2012 / 12:10
1

Sendo um pouco preguiçoso, não demorou muito para encontre um on-line .

Primeiro você precisa criar uma soma de verificação CRC de cada arquivo, já que, obviamente, você só deseja remover duplicatas exatas.

cksum  *.jpg | sort -n > filelist

Em seguida, repita essa lista de arquivos, lendo a soma de verificação e também o nome do arquivo. Se duas somas de verificação forem as mesmas, o arquivo será removido. Isso funciona, pois a classificação é numérica e apenas ordena as somas de verificação, que agrupam arquivos duplicados.

old=""
while read sum lines filename
do
      if [[ "$sum" != "$old" ]] ; then
            old="$sum"
            continue
      fi
      rm -f "$filename"
done < filelist

Obviamente, isso não funciona de forma recursiva.

    
por 05.02.2012 / 12:14
1

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 dessa lista e verificar se os nomes deles 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 algumas dir:

$> 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 com folhas.

$> ls .tmp/ -1
all.txt
file
text(2)
    
por 05.02.2012 / 12:17
1

Eu escrevi este minúsculo script para excluir arquivos duplicados

link

Basicamente, ele usa um arquivo temporário ( /tmp/list.txt ) para criar um mapa de arquivos e seus hashes. Mais tarde, eu uso esses arquivos e a magia dos pipes Unix para fazer o resto.

O script não apaga nada, mas imprime os comandos para excluir arquivos.

mfilter.sh ./dir | bash

Espero que ajude

    
por 28.05.2013 / 05:00
1

Versão mais concisa de remoção de arquivos duplicados (apenas uma linha)

young@ubuntu-16:~/test$ md5sum 'find ./ -type f' | sort -k1 | uniq -w32 -d | xargs rm -fv

find_same_size.sh

#!/usr/bin/env bash
#set -x
#This is small script can find same size of files.
find_same_size(){

if [[ -z $1 || ! -d $1 ]]
then
echo "Usage $0 directory_name" ;
 exit $?
else
dir_name=$1;
echo "current directory is $1"



for i in $(find $dir_name -type f); do
   ls -fl $i
done | awk '{f=""
        if(NF>9)for(i=9;i<=NF;i++)f=f?f" "$i:$i; else f=$9;
        if(a[$5]){ a[$5]=a[$5]"\n"f; b[$5]++;} else a[$5]=f} END{for(x     in b)print a[x] }' | xargs stat -c "%s  %n" #For just list files
 fi
   }

find_same_size $1


young@ubuntu-16:~/test$ bash find_same_size.sh tttt/ | awk '{ if($1 !~   /^([[:alpha:]])+/) print $2}' | xargs md5sum | uniq -w32 -d | xargs rm -vf
    
por 28.08.2016 / 10:07
0

Encontrei uma maneira mais fácil de realizar a mesma tarefa

for i in 'md5sum * | sort -k1 | uniq -w32 -d|awk '{print $2}''; do
rm -rf $i
done
    
por 21.11.2015 / 07:40
0

A maioria e possivelmente todas as respostas restantes são terrivelmente ineficientes, calculando a soma de verificação de cada arquivo no diretório para processar.

Uma abordagem potencialmente mais rápida é primeiro obter o tamanho de cada arquivo, que é quase imediato ( ls ou stat ), e depois calcular e comparar as somas de verificação apenas para os arquivos com tamanho não exclusivo. .

    
por 28.08.2016 / 10:41
0

Não é isso que você está perguntando, mas acho que alguém pode achar útil quando as somas de verificação não são as mesmas, mas o nome é semelhante (com o sufixo entre parênteses). Este script remove os arquivos com sufixos como ("dígito")

#! /bin/bash
# Warning: globstar excludes hidden directories.
# Turn on recursive globbing (in this script) or exit if the option is not supported:
shopt -s globstar || exit
for f in **
do
extension="${f##*.}"
#get only files with parentheses suffix
FILEWITHPAR=$( echo "${f%.*}".$extension | grep -o -P "(.*\([0-9]\)\..*)")
# print file to be possibly deleted
if [ -z "$FILEWITHPAR" ] ;then
:
else
echo "$FILEWITHPAR ident"
# identify if a similar file without suffix exists
FILENOPAR=$(echo $FILEWITHPAR | sed -e 's/^\(.*\)([0-9])\(.*\).*//')
echo "$FILENOPAR exists?"
if [ -f "$FILENOPAR" ]; then
#delete file with suffix in parentheses
echo ""$FILEWITHPAR" to be deleted"
rm -Rf "$FILEWITHPAR"
else
echo "no"
fi
fi
done
    
por 12.12.2017 / 14:22
-3

Eu encontrei um pequeno programa que realmente simplifica este tipo de tarefas: fdupes .

    
por 21.09.2018 / 04:48

Tags