Existe uma maneira de excluir duplicatas mais refinada que fdupes -rdN?

Existe uma maneira de excluir duplicatas mais refinada que fdupes -rdN?

Recentemente, tive a necessidade de excluir muitas duplicatas. Estou mesclando três ou quatro sistemas de arquivos e quero que o espaço seja usado economicamente. A princípio fdupesparecia a melhor ferramenta para o trabalho, mas cada vez mais encontro limitações.

Considere o comando fdupes -rdN somedirectory/. Isso cria um hash de todos os arquivos nos subdiretórios de algum diretório.

E quando encontra duplicatas, ele as apaga, para que haja apenas uma cópia de tudo.

Mas e se eu quiser manter somedirectory/subdirectory1/somefilee houver, de fato, quatro duplicatas, e o programa encontrar uma das duplicatas primeiro? Então ele exclui somedirectory/subdirectory1/somefile, o que eu não quero.

Quero poder especificar, de alguma forma, quais duplicatas manter. E até agora, nenhum dos programas padrão para lidar com duplicatas (duff, FSLint) parece permitir a automação desse tipo de comportamento. Eu preferiria não fazer o meu próprio, é por isso que estou fazendo esta pergunta.

Eu gostaria de poder escrever algo como

killdupes -rdN --keep=filesin,somedirectories,separated,by,commas somedirectory/

Responder1

Embora a funcionalidade que você procura não esteja disponível em estoque fdupes, eu bifurqueifdupes (meu garfo se chama jdupes)e adicionou alguns recursos que podem resolver esse problema em determinadas circunstâncias. Por exemplo, no caso declarado em que você deseja manter somedirectory/subdirectory1/somefileao excluir automaticamente duplicatas (as opções de Njuntas) e não há arquivos separados imediatamente abaixo de somedirectory, jdupespode ser alimentado cada caminho de subdiretório imediato com subdirectory1first e a -Oopção (que classifica os arquivos por comando -line ordem dos parâmetros primeiro):

jdupes -rdNO somedirectory/subdirectory1 somedirectory/subdirectory2 somedirectory/subdirectory3

Isso excluirá automaticamente todos os arquivos, exceto um, em um conjunto duplicado e garantirá que, se o conjunto contiver um arquivo, somedirectory/subdirectory1ele será o primeiro, tornando-se automaticamente o arquivo preservado no conjunto. Ainda existem limites evidentes para essa abordagem, como o fato de que outra duplicata somedirectory/subdirectory1pode ser preservada em vez daquela que você deseja manter, mas em um bom número de casos como o seu, a jdupesopção de ordem de parâmetro como solução alternativa é boa o suficiente.

Num futuro próximo, pretendo adicionar um sistema de filtragem jdupesque permitirá um enorme controle sobre a inclusão/exclusão de arquivos, preservação para -Nações e aplicação de tais "pilhas de filtros" de forma global ou por parâmetro. Este recurso é extremamente necessário; Eu imagino algo assim para "excluir automaticamente duplicatas diferentes de zero recursivamente, MAS sempre preservar somedirectory/subdirectory1/somefilecomo estão":

jdupes -rdN --filter=preserve:somedirectory/subdirectory1/somefile somedirectory/

ATUALIZAÇÃO (01/03/2022):Dê uma olhada nas -Xopções de filtro estendido adicionadas em 2020. Não é exatamente o que você deseja, mas os filtros nostre onlystrpermitem especificar substrings dentro de um caminho completo para ignorar ou exigir.

Responder2

Não vi este em nenhum outro lugar: diga o que você quer é isso. Você tem /mnt/folder-tree-1 /mnt/folder-tree-2. Você não deseja remover todos os idiotas, mas se existir um arquivo na árvore-2 e um arquivo idêntico existir na árvore-1 com exatamente o mesmo caminho e nome, remova-o da árvore-2.

Aviso: isso é bastante conciso e se você tentar copiar e colar com habilidades limitadas de shell, tome cuidado.

fdupes -rn /mnt/folder-tree-1/ /mnt/folder-tree-2/ > dupes-all.txt

fgrep /mnt/folder-tree-1/ dupes-all.txt | while read line
do
if grep -q "`echo $line | sed -e 's|^/mnt/folder-tree-1/|/mnt/folder-tree-2/|'`" dupes-all.txt
then
    echo rm \"$(echo $line | sed -e 's|^/mnt/folder-tree-1/|/mnt/folder-tree-2//|')\"
fi
done > rm-v2-dupes.sh

Ou tudo em uma linha:

fdupes -rn /mnt/folder-tree-1/ /mnt/folder-tree-2/ > dupes-all.txt; fgrep /mnt/folder-tree-1/ dupes-all.txt | while read line; do if grep -q "`echo $line | sed -e 's|^/mnt/folder-tree-1/|/mnt/folder-tree-2/|'`" dupes-all.txt; then echo rm \"$(echo $line | sed -e 's|^/mnt/folder-tree-1/|/mnt/folder-tree-2/|')\"; fi; done > rm-v2-dupes.sh

Depois, inspecione e execute rm-v2-dupes.sh

Responder3

Que tal vincular os arquivos duplicados? Dessa forma o espaço é utilizado apenas uma vez, mas ainda existem em todos os caminhos. O problema é que os arquivos com link físico devem ser modificados no local (eles só devem ser modificados excluindo o arquivo e recriando-o com o novo conteúdo). A outra abordagem é vincular os arquivos simbolicamente, embora você tenha o mesmo problema ao decidir qual é o arquivo "primário". Isso poderia ser feito com o script a seguir (embora observe que isso não lida com nomes de arquivos contendo espaços).

fdupes --quiet --recurse --sameline somedirectory/ | while read SOURCE DESTS; do
    for DEST in $DESTS; do
        ln -f $SOURCE $DEST
    done
done

Responder4

Apenas para adicionar um toque especial a uma resposta anterior. Usei o código a seguir várias vezes, modificando ligeiramente uma resposta anterior com um simples | grepisolamento da pasta da qual desejo excluir.

`fdupes -r -n -S /directory | grep /delete-from-directory | sed -r "s/^/rm \"/" | sed -r "s/$/\"/" >remove-duplicate-files.sh`

Novamente, isso criará um arquivo sh para excluir todos os arquivos listados, sem linhas comentadas. É claro que você ainda pode editar o arquivo para comentar linhas/arquivos específicos que deseja manter.

Outra dica para diretórios grandes é executar fdupes em um arquivo txt e experimentar | grepe | sedaté obter o resultado desejado.

`fdupes -r -n -S /directory > duplicate-files.txt`
`cat duplicate-files.txt | grep /delete-from-directory | sed -r "s/^/rm \"/" | sed -r "s/$/\"/" >remove-duplicate-files.sh`

informação relacionada