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 de maneira econômica. No início, fdupes parecia ser a melhor ferramenta para o trabalho, mas estou cada vez mais encontrando 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, as apaga, de modo que há apenas uma cópia de tudo.

Mas e se eu quiser manter somedirectory/subdirectory1/somefile e existem, de fato, quatro duplicatas, e o programa encontra uma das duplicatas primeiro? Em seguida, ele exclui somedirectory/subdirectory1/somefile, que eu não quero.

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

Eu “gostaria de poder escrever algo como

Comentários

Resposta

Embora a funcionalidade que você busca não esteja disponível em estoque fdupes, eu bifurquei fdupes (meu fork se chama jdupes) e adicionou alguns recursos que podem resolver esse problema em certas circunstâncias. exemplo, no caso indicado em que deseja manter somedirectory/subdirectory1/somefile ao excluir duplicatas automaticamente (as chaves d e N juntas) e não há arquivos separados imediatamente abaixo de somedirectory, jdupes pode ser alimentado em cada caminho de subdiretório imediato com subdirectory1 primeiro e o -O switch (que classifica os arquivos pela ordem dos parâmetros da linha de comando primeiro):

jdupes -nrdNO somedirectory/subdirectory1 somedirectory/subdirectory2 somedirectory/subdirectory3

Isso irá excluir automaticamente todos os arquivos, exceto um em um conjunto duplicado e garantirá que se o conjunto contiver um arquivo em somedirectory/subdirectory1, ele será o primeiro, tornando-se automaticamente o arquivo preservado no conjunto . Ainda há limites flagrantes para essa abordagem, como o fato de que outra duplicata em somedirectory/subdirectory1 pode ser preservada em vez da que você deseja manter, mas em um bom número de casos como o seu, a opção de ordem do parâmetro jdupes como uma solução alternativa é boa o suficiente.

Em um futuro próximo, pretendo adicionar um sistema de filtragem a jdupes que permitirá uma grande quantidade de controle sobre a inclusão / exclusão de arquivos, preservação para -N ações e aplicação de tais “pilhas de filtros” em um global ou por -parâmetro base. Esse recurso é extremamente necessário; Eu imagino algo assim para “excluir automaticamente duplicatas diferentes de zero recursivamente, MAS sempre preservar somedirectory/subdirectory1/somefile como está”:

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

Resposta

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

Aviso: é muito conciso e se você tentar copiar e colar com habilidades de shell limitadas, tenha 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

Resposta

Que tal vincular os arquivos duplicados juntos? Dessa forma o espaço é usado apenas uma vez, mas eles ainda existem em todos os caminhos. O problema com isso é 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 simbolicamente os arquivos, embora você tenha o mesmo problema de decidir qual é o arquivo “principal”. Isso poderia ser feito com o seguinte script (embora observe que ele não lida com nomes de arquivo que contenham espaços).

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

Comentários

  • Usando jdupes em vez de fdupes você pode simplesmente ir jdupes -nrL somedirectory/ que é muito mais rápido.
  • Digitação no link para jdupes. Link de conveniência: github.com/jbruchon/jdupes

Resposta

Eu tinha a mesma pergunta.Se você tiver muitas duplicatas, fdupes /my/directory/ -rdN mantém o arquivo com a data de modificação mais antiga, ou se vários arquivos têm a mesma data de modificação, então aquele encontrado primeiro.

Se a data de modificação não for importante para você, você pode touch os arquivos no diretório que deseja manter. Se você escolher touch com a data e hora atuais, fdupes -rdNi manterá aqueles com a data atual. Ou você pode touch manter os arquivos com uma data anterior àquela que deseja excluir e usar fdupes -rdN normalmente.

Se precisar manter a data de modificação, você precisará usar um dos outros métodos.

Resposta

Apenas para adicionar um toque a uma resposta anterior. Eu usei o código a seguir várias vezes, modificando ligeiramente uma resposta anterior com um simples | grep para isolar a 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, em seguida, experimentar | grep e | sed até eu obter o resultado que eu quero.

`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` 

Resposta

Use sed para criar um arquivo shell que conterá comandos comentados para excluir cada um de seus arquivos duplicados:

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

O remove-duplicate-files.sh fil O que acabamos de criar terá cada linha comentada. Remova o comentário dos arquivos que deseja excluir. Em seguida, execute sh remove-duplicate-files.sh . Voila!

ATUALIZAÇÃO

Bem, se você não quiser excluir arquivos apenas em determinados diretórios, é tão simples quanto este :

fdupes -S /directory|sed "/^$/d" |sed -r "s/^[0-9]/#&/" > duple_list python exclude_duplicates.py -f /path/to/dupe_list --delimiter="#" --keep=/full/path/to/protected/directory1,/full/path/to/protected/directory2\ with\ spaces\ in\ path >remove-duplicate-files-keep-protected.sh 

Onde exclude_duplicates.py é:

 #/usr/bin/python # -*- coding: utf-8 -*- # exclude_duplicates.py """ THE SCRIPT DOESN"T DELETE ANYTHING, IT ONLY GENERATES TEXT OUTPUT. Provided a list of duplicates, such as fdupes or fslint output, generate a bash script that will have all duplicates in protected directories commented out. If none of the protected duplicates are found in a set of the same files, select a random unprotected duplicate for preserving. Each path to a file will be transformed to an `rm "path"` string which will be printed to standard output. """ from optparse import OptionParser parser = OptionParser() parser.add_option("-k", "--keep", dest="keep", help="""List of directories which you want to keep, separated by commas. \ EXAMPLE: exclude_duplicates.py --keep /path/to/directory1,/path/to/directory\ with\ space\ in\ path2""", metavar="keep" ) parser.add_option("-d", "--delimiter", dest="delimiter", help="Delimiter of duplicate file groups", metavar="delimiter" ) parser.add_option("-f", "--file", dest="file", help="List of duplicate file groups, separated by delimiter, for example, fdupes or fslint output.", metavar="file" ) (options, args) = parser.parse_args() directories_to_keep = options.keep.split(",") file = options.file delimiter = options.delimiter pretty_line = "\n#" + "-" * 35 print "#/bin/bash" print "#I will protect files in these directories:\n" for d in directories_to_keep: print "# " + d print pretty_line protected_set = set() group_set = set() def clean_set(group_set, protected_set, delimiter_line): not_protected_set = group_set - protected_set while not_protected_set: if len(not_protected_set) == 1 and len(protected_set) == 0: print "#randomly selected duplicate to keep:\n#rm "%s"" % not_protected_set.pop().strip("\n") else: print "rm "%s"" % not_protected_set.pop().strip("\n") for i in protected_set: print "#excluded file in protected directory:\n#rm "%s"" % i.strip("\n") print "\n#%s" % delimiter_line file = open(file, "r") for line in file.readlines(): if line.startswith(delimiter): clean_set(group_set, protected_set, line) group_set, protected_set = set(), set() else: group_set = group_set|{line} for d in directories_to_keep: if line.startswith(d): protected_set = protected_set|{line} else: if line: clean_set(group_set, protected_set, line)  

O resultado remove-duplicate-files-keep-protected.sh arquivo que acabamos de criar terá todos os arquivos de diretórios protegidos comentados. Abra este arquivo em seu editor de texto favorito, verifique se está tudo OK. Em seguida, execute-o. Voila (sic)!

Comentários

  • eu pensei nisso, mas ‘ não é automatizado o suficiente. Estupidamente, eu causei perda de dados com este método quando lidar com duplicatas espaçadas em vários sistemas de arquivos … não há ‘ nenhuma maneira de atribuir uma prioridade, dada a saída de fdup es. basicamente, eu teria que vasculhar 10.000 arquivos manualmente para evitar a perda de dados … então, não, obrigado … na verdade, essa perda de dados é a razão pela qual fiz esta pergunta.
  • @ixtmixilix, bem, o método manual depende da atenção do usuário, aqui ‘ não há nada de novo. Se você quiser algo mais automatizado, verifique uma resposta atualizada acima.

Resposta

Que tal algo assim?

#!/bin/bash DUPE_SEARCH_DIR=somedir/ PREFERRED_DIRS=("somedir/subdir1" "somedir/subdir2") DUPE_FILE=/tmp/`basename $0`_found-duplicates delete_dupes() { while read line ; do if [ -n "$line" ] ; then matched=false for pdir in "${PREFERRED_DIRS[@]}" ; do if [[ $line == $pdir/* ]] ; then matched=true break fi done if ! $matched ; then rm -v "$line" fi fi done < "$DUPE_FILE" } cleanup() { rm -f $DUPE_FILE } trap cleanup EXIT # get rid of normal dupes, preserve first & preserve preferred fdupes -rf "$DUPE_SEARCH_DIR" > $DUPE_FILE delete_dupes # get rid of preserve dupes, preserve preferred fdupes -r "$DUPE_SEARCH_DIR" > "$DUPE_FILE" delete_dupes 

Resposta

A partir do Apple Filesystem (APFS), outra solução é manter os arquivos, desduplicá-los e não ter impacto no uso do disco. Veja Substituir arquivos duplicados existentes no APFS por clones

Deixe uma resposta

O seu endereço de email não será publicado. Campos obrigatórios marcados com *