Fdupes -rdN öğesinden daha zarif kopyaları silmenin bir yolu var mı?


22

Son zamanlarda birçok kopyayı silmeye ihtiyacım var. Üç veya dört dosya sistemini birleştiriyorum ve alanın ekonomik olarak kullanılmasını istiyorum. İlk başta, fdupesiş için en iyi araç gibiydi, ama giderek daha çok kısıtlamalar ile karşılaşıyorum.

Komutu düşün fdupes -rdN somedirectory/. Bu, bazı dizinlerin alt dizinlerindeki tüm dosyaların bir özetini yapar.

Ve kopyalarla karşılaştığında, onları siler, böylece her şeyin sadece bir kopyası olur.

Peki ya saklamak istersem somedirectory/subdirectory1/somefile, aslında dört kopya varsa ve program ilk önce kopyalardan biriyle karşılaştığında? Sonra somedirectory/subdirectory1/somefileistemediğim siler .

Bir şekilde saklanacak kopyaları belirleyebilmek istiyorum. Ve şimdiye kadar, yinelemelerle (duff, FSLint) ilgili standart programların hiçbiri bu tür davranışların otomasyonuna izin vermiyor gibi görünmektedir. Kendime gelmemeyi tercih ederim, bu yüzden bu soruyu soruyorum.

Gibi bir şey yazabilmek istiyorum

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

Ben de aynı şeyi arıyordu ve bunu buldum superuser.com/a/561207/218922
Alexis

Yanıtlar:


5

Aradığın işlevselliği stokta mevcut olmasa da fdupes, ben çatallıfdupes ( denir jdupes) ve bu şartı belirli durumlarda çözebilecek bazı özellikler ekledim. Örneğin, somedirectory/subdirectory1/somefileyinelenenleri otomatik olarak silerken ( dve Nbirlikte geçer) ve hemen altında ayrı bir dosya bulunmadığında saklamak istediğiniz belirtilen durumda ve hemen altında ayrı bir dosya bulunmazsa somedirectory, jdupesher bir alt dizin yoluna subdirectory1önce ve -Oanahtarla (dosyaları komutla sıralayan) beslenebilir. -line parametre sırası önce):

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

Bu, yinelenen bir kümedeki tek bir dosyayı hariç tümünü otomatik olarak siler ve kümede bir dosya varsa, somedirectory/subdirectory1bunun otomatik olarak kümede korunan bir dosya olmasını garanti eder . Saklamak somedirectory/subdirectory1istediğiniz yerine başka bir kopyanın korunabileceği gerçeği gibi hala bu yaklaşım için göze çarpan sınırlar var , ancak sizinki gibi çok sayıda durumda, jdupesgeçici çözüm olarak parametre sırası seçeneği yeterince iyi.

Yakın gelecekte, bir filtreleme sistemi eklemeyi planlıyorum jdupes dosyaların dahil edilmesi / hariç tutulması, -Neylemlerin korunması ve bu tür "filtre yığınlarının" küresel ya da parametre bazında uygulanmasında büyük miktarda kontrol sağlayacak . Bu özelliğe şiddetle ihtiyaç var; "Sıfır olmayan yinelemeleri özyinelemeli otomatik sil" ANCAK her zaman somedirectory/subdirectory1/somefileolduğu gibi koruyacak ":

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


4

Yinelenen dosyaları bir araya getirmeye ne dersiniz? Bu şekilde, alan yalnızca bir kez kullanılır, ancak yine de tüm yollarda bulunurlar. Bununla ilgili bilgi, hardlinkli dosyaların yerinde değiştirilmeleri gerektiğidir (sadece dosyayı silip yeni içerikle yeniden oluşturmaları gerekir). Diğer yaklaşım, dosyaları "birbirine bağlamak" olmasına rağmen, "birincil" dosyanın hangisi olduğuna karar vermede aynı sorunun olmasına rağmen. Bu, aşağıdaki komut dosyasıyla yapılabilir (bunun boşluk içeren dosya adlarını işlemeyeceğini unutmayın).

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

1
Siz jdupesyerine kullanmak fdupes, basitçe jdupes -nrL somedirectory/daha hızlı olan bir şey olabilir .
Jody Lee Bruchon

1
Jdupes bağlantısını yazım hatası. Kolaylık bağlantısı: github.com/jbruchon/jdupes
Royce Williams

4

Bunu başka hiçbir yerde görmedim: İstediğin şeyin bu olduğunu söyle. Siz / mnt / klasör ağacı-1 / mnt / klasör ağacı-2'niz var. Her dupe'yi kaldırmak istemezsiniz, ancak tree-2'de bir dosya varsa ve tree-1'de tam olarak aynı yol ve adla aynı dosya varsa, tree-2'den kaldırın.

Uyarı: Bu oldukça özlü ve bunu sınırlı kabuk becerileri ile kopyalayıp yapıştırmaya çalışırsanız, dikkatli olun.

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

Ya da hepsi bir satırda:

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

Daha sonra rm-v2-dupes.sh dosyasını inceleyin ve uygulayın.


4

Ben de aynı soruyu yaşadım. Çok sayıda yinelemeniz varsa fdupes /my/directory/ -rdN, dosyayı en eski değişiklik tarihiyle tutarsa ​​veya birkaç dosya aynı değişiklik tarihine sahipse, ilk önce bu dosyayı bulur.

Değiştirme tarihi sizin için önemli değilse, touchsaklamak istediğiniz dizindeki dosyaları yapabilirsiniz . touchOnları geçerli tarih ve saatle seçerseniz o zamanları geçerli tarihle fdupes -rdNitutacaktır. Ya da yapabilirsintouch , dosyaları silmek istediğiniz dosyalardan daha eski bir tarihte tutabilir ve fdupes -rdNnormal olarak kullanabilirsiniz .

Değişiklik tarihini korumanız gerekirse, diğer yöntemlerden birini kullanmanız gerekecektir.


3

Sadece önceki bir cevaba bir twist eklemek için. Aşağıdaki kodu birkaç kez kullandım, | grepsilmek istediğim klasörü basitleştirmek için önceki bir cevabı biraz değiştirdim .

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

Yine, bu listelenen tüm dosyaları silmek için bir sh dosyası oluşturacaktır, yorumlanan satır yok. Elbette, tutmak istediğiniz belirli satırları / dosyaları yorumlamak için dosyayı hala düzenleyebilirsiniz.

Büyük dizinler için başka bir ipucu fdupes'i bir txt dosyasına çalıştırmak, sonra istediğim sonucu elde edene kadar | grepve ile deneme | sedyapmak.

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

2

sedÇift dosyalarınızın her birini silmek için yorumlanmış komutlar içerecek bir kabuk dosyası oluşturmak için kullanın :

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

Yeni yarattığımız sonuçta ortaya çıkan remove-duplicate-files.shdosya her satırda yorumlanacaktır. Silmek istediğiniz dosyaları uncomment. O zaman koş sh remove-duplicate-files.sh. İşte bu kadar!

GÜNCELLEŞTİRME

Eh, sadece belirli dizinlerdeki dosyaları silmek istemiyorsanız, bu kadar basit :

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

Nerede 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)

Yeni oluşturduğumuz ortaya çıkan remove-duplicate-files-keep-protected.shdosya, korumalı dizinlerden gelen tüm dosyaları yorumlayacaktır. Bu dosyayı favori metin düzenleyicinizde açın, her şeyin yolunda olup olmadığını kontrol edin. O zaman çalıştır. Voila (sic)!


Bunu düşündüm, ama yeterince otomatik değil. aptalca, birden fazla dosya sistemine aralıklı kopyalarla uğraşırken bu yöntemle veri kaybına neden oldum ... fdup'ların çıktısı göz önüne alındığında öncelik atamanın bir yolu yok. Temelde bu veri kaybını önlemek için elle 10000 dosya arasında dolaşmak zorunda kalacağım ... bu yüzden, hayır ... aslında, bu soruyu sormamın sebebi veri kaybı.
ixtmixilix

@ixtmixilix, peki, manuel yöntem kullanıcının dikkatine bağlıdır, işte yeni bir şey yok. Daha otomatik bir şey istiyorsanız, yukarıda güncellenmiş bir cevabı kontrol edin.
Ivan Kharlamov

2

Böyle bir şeye ne dersin?

#!/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
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.