localiza e remove nomes de arquivos duplicados na hierarquia de diretórios

3
#!/bin/sh
LASTBASE=""  
find $1 -type f -print | rev | sort | rev | while read FILE
do
    BASE=$(basename "$FILE")
    if [ "$BASE" = "$LASTBASE" ]; then
        rm "$FILE"
    LASTBASE="$BASE"
done
    
por StefanoCudini 06.02.2013 / 19:59

3 respostas

3

Se você enviar a saída de find em um loop while read , você poderá lidar com eles linha por linha:

find nnn/ -type f -print | rev | sort | rev | while read FILE; do
    ...
done

Editar : Então, este método quebra se nomes de arquivos contêm espaços duplos (consecutivos), porque read divide a linha de acordo com $IFS e, em seguida, une novamente ao armazenar a última variável . Para resolver isso, você pode alterar temporariamente $IFS para desabilitar a divisão:

OIFS="$IFS"
IFS=""
find | while read...
IFS="$OIFS"

Editar : test (que é o mesmo que [ ) não tem um operador == , você só quer = .

    
por 06.02.2013 / 20:05
2

Acabei de encontrar esse "gem" em um antigo histórico bash e, na verdade, funciona sem tropeçar em espaços em branco em nomes de arquivos.

Comparação de conteúdo

for hash in 'find . -exec md5sum {} \; 2>/dev/null | sort | awk '{ print $1 }' | uniq -d'; do 
     find . -exec md5sum {} \; 2>/dev/null | grep $hash | awk '{print $2 }'; 
done;

informal:

  • Primeira linha: percorra a árvore de diretórios e calcule o md5sum de todos os arquivos abaixo, classifique essa saída (formato: hash filename), pegue a coluna hash, reduza para valores duplicados. (significa que há duplicatas)
  • Segunda linha: para cada um dos hashes de duas ocorrências, percorra novamente e imprima o nome do arquivo se o arquivo atual tiver o hash atual (significa que o arquivo é múltiplo)
Exemplo de saída

:

./aFile
./aFolder/aFile
./1000digitsOfPI
./a/b/c/thousanddigitsofPI
./b File
./bFolder/cFolder/b File

A remoção não está implementada aqui porque pode ser difícil decidir qual versão dos arquivos duplicados você deseja manter.

Comparação com nome de arquivo

Se você quiser apenas ver nomes de arquivos e não conteúdos, fica ainda mais fácil:

for name in 'find . -type f -printf "%f\n" | sort | uniq -d'; do 
    find . -name $name; 
done;

Atualização: Infelizmente esta versão está quebrando com espaços em branco em nomes de arquivos novamente.

    
por 06.02.2013 / 22:43
1

O problema está nessa linha de código for FILE in $FILES; do - o loop for está atribuindo a variável FILE com base no separador de espaço em branco. Portanto, se um arquivo tiver um ou mais espaços em branco, não funcionará. Basta alterar o IFS padrão do espaço para uma nova linha ou guia. Se bem me lembro, você pode definir o IFS no bash usando algo assim -

IFS = $ '\ n'

    
por 06.02.2013 / 20:30

Tags