Có cách nào để xóa các bản sao được tinh chỉnh hơn fdupes -rdN không?


22

Gần đây tôi có nhu cầu xóa rất nhiều bản sao. Tôi đang hợp nhất ba hoặc bốn hệ thống tập tin và tôi muốn không gian được sử dụng một cách kinh tế. Lúc đầu, fdupescó vẻ như đó là công cụ tốt nhất cho công việc, nhưng tôi ngày càng gặp nhiều hạn chế.

Hãy xem xét lệnh fdupes -rdN somedirectory/. Điều này tạo ra một hàm băm của tất cả các tệp trong thư mục con của somedirectory.

Và khi nó gặp phải các bản sao, nó sẽ xóa chúng, do đó chỉ có một bản sao của mọi thứ.

Nhưng điều gì sẽ xảy ra nếu tôi muốn giữ somedirectory/subdirectory1/somefilevà trên thực tế, có bốn bản sao và chương trình gặp một trong những bản sao đầu tiên? Sau đó, nó xóa somedirectory/subdirectory1/somefile, mà tôi không muốn.

Tôi muốn có thể chỉ định, bằng cách nào đó, trùng lặp để giữ. Và cho đến nay, không có chương trình tiêu chuẩn nào để xử lý các bản sao (duff, FSLint) dường như cho phép tự động hóa loại hành vi đó. Tôi không muốn tự lăn, vì vậy đó là lý do tại sao tôi hỏi câu hỏi này.

Tôi muốn có thể viết một cái gì đó như

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

Tôi đang tìm kiếm điều tương tự và tôi đã tìm thấy superuser
này.com

Câu trả lời:


5

Mặc dù chức năng bạn tìm kiếm không có sẵn trong kho fdupes, tôi đã rẽ nhánh fdupes (ngã ba của tôi được gọi jdupes) và thêm một số tính năng có thể giải quyết vấn đề này trong một số trường hợp nhất định. Ví dụ, trong trường hợp đã nêu mà bạn muốn giữ somedirectory/subdirectory1/somefilekhi tự động xóa các bản sao ( dvà và Nchuyển đổi cùng nhau) và không có tệp riêng biệt ngay bên dưới somedirectory, jdupescó thể được cung cấp từng đường dẫn thư mục con ngay lập tức bằng lệnh subdirectory1đầu tiên và -Ochuyển đổi (sắp xếp các tệp theo lệnh thứ tự tham số dòng đầu tiên):

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

Điều này sẽ tự động xóa tất cả trừ một tệp trong một bộ trùng lặp và sẽ đảm bảo rằng nếu tập hợp chứa tệp trong somedirectory/subdirectory1đó sẽ là tệp đầu tiên, do đó tự động trở thành tệp được bảo tồn trong tập hợp. Vẫn còn những giới hạn rõ ràng cho cách tiếp cận này, chẳng hạn như một bản sao khác somedirectory/subdirectory1có thể được bảo tồn thay vì cách bạn muốn giữ, nhưng trong một số trường hợp tốt như của bạn, jdupestùy chọn thứ tự tham số như một cách giải quyết là đủ tốt.

Trong tương lai gần, tôi dự định thêm một hệ thống lọc vào jdupesđó sẽ cho phép một lượng lớn quyền kiểm soát đối với việc bao gồm / loại trừ các tệp, bảo quản cho -Ncác hành động và áp dụng các "ngăn xếp bộ lọc" đó trên cơ sở toàn cầu hoặc theo tham số. Tính năng này rất cần thiết; Tôi hình dung một cái gì đó như thế này để "tự động xóa các bản sao khác không đệ quy NHƯNG luôn giữ nguyên trạng somedirectory/subdirectory1/somefile":

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


4

Điều gì về liên kết cứng các tập tin trùng lặp với nhau? Bằng cách đó, không gian chỉ được sử dụng một lần, nhưng chúng vẫn tồn tại trong tất cả các đường dẫn. Điều hấp dẫn ở đây là các tệp liên kết cứng nên được sửa đổi tại chỗ (chúng chỉ nên được sửa đổi để xóa tệp và tạo lại nó với nội dung mới). Cách tiếp cận khác là liên kết các tệp với nhau, mặc dù bạn có cùng một vấn đề quyết định tệp "chính" là gì. Điều này có thể được thực hiện với đoạn script sau (mặc dù lưu ý rằng điều này không xử lý tên tệp có chứa khoảng trắng).

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

1
Sử dụng jdupesthay vì fdupesbạn có thể chỉ đơn giản là đi jdupes -nrL somedirectory/nhanh hơn.
Jody Lee Bruchon

1
Typo trong liên kết đến jdupes. Liên kết tiện lợi: github.com/jbruchon/jdupes
Royce Williams

4

Tôi đã không thấy cái này ở bất cứ nơi nào khác: Nói những gì bạn muốn là cái này. Bạn có / mnt / thư mục-cây-1 / mnt / thư mục-cây-2. Bạn không muốn xóa mọi bản sao, nhưng nếu một tệp tồn tại trong cây-2 và một tệp giống hệt tồn tại trong cây-1 với cùng một đường dẫn và tên chính xác, hãy xóa nó khỏi cây-2.

Cảnh báo: điều này khá ngắn gọn và nếu bạn cố gắng sao chép-dán nó với các kỹ năng vỏ hạn chế, hãy cẩn thận.

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

Hoặc tất cả trên một dòng:

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

Sau đó, kiểm tra và thực hiện rm-v2-dupes.sh


4

Tôi đã có cùng một câu hỏi. Nếu bạn có nhiều bản sao fdupes /my/directory/ -rdNgiữ tệp có ngày sửa đổi cũ nhất hoặc nếu một số tệp có cùng ngày sửa đổi, thì tệp được tìm thấy trước.

Nếu ngày sửa đổi không quan trọng đối với bạn, bạn có thể lưu touchcác tệp trong thư mục bạn muốn giữ. Nếu bạn chọn touchchúng với ngày và giờ hiện tại thì fdupes -rdNisẽ giữ những ngày có ngày hiện tại. Hoặc bạn có thể touchgiữ các tệp có ngày sớm hơn các tệp bạn muốn xóa và sử dụng fdupes -rdNnhư bình thường.

Nếu bạn cần giữ ngày sửa đổi, thì bạn sẽ cần sử dụng một trong các phương pháp khác.


3

Chỉ cần thêm một twist cho một câu trả lời trước đó. Tôi đã sử dụng mã sau nhiều lần, sửa đổi một chút câu trả lời trước đó bằng một cách đơn giản | grepđể tách thư mục tôi muốn xóa.

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

Một lần nữa, điều này sẽ tạo một tệp sh để xóa tất cả các tệp được liệt kê, không có dòng nhận xét. Tất nhiên bạn vẫn có thể chỉnh sửa tệp để nhận xét các dòng / tệp cụ thể mà bạn muốn giữ.

Một gợi ý khác cho các thư mục lớn là chạy fdupes vào tệp txt, sau đó thử nghiệm | grep| sedcho đến khi tôi nhận được kết quả mình muốn.

`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

Sử dụng sedđể tạo một tệp shell sẽ chứa các lệnh nhận xét để xóa từng tệp trùng lặp của bạn:

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

Tệp kết quả remove-duplicate-files.shmà chúng tôi vừa tạo sẽ có từng dòng nhận xét. Bỏ ghi chú các tập tin bạn muốn xóa. Sau đó chạy sh remove-duplicate-files.sh. Voila!

CẬP NHẬT

Chà, nếu bạn không muốn xóa các tệp chỉ trong một số thư mục nhất định, thì đơn giản như sau :

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

Ở đâu 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)

Tệp kết quả remove-duplicate-files-keep-protected.shmà chúng tôi vừa tạo sẽ có tất cả các tệp từ các thư mục được bảo vệ nhận xét. Mở tệp này trong trình soạn thảo văn bản yêu thích của bạn, kiểm tra xem mọi thứ đều ổn. Sau đó chạy nó. Voila (sic)!


Tôi nghĩ về điều này, nhưng nó không đủ tự động. thật ngu ngốc, tôi đã gây mất dữ liệu với phương thức này khi xử lý các bản sao được đặt cách nhau trên nhiều hệ thống tập tin ... không có cách nào để gán mức độ ưu tiên, dựa trên đầu ra của fdupes. về cơ bản tôi sẽ phải duyệt qua 10000 tệp bằng tay để ngăn chặn việc mất dữ liệu đó ... vì vậy, không, cảm ơn ... thực tế, việc mất dữ liệu là lý do tôi hỏi câu hỏi này.
ixtmixilix

@ixtmixilix, tốt, phương pháp thủ công phụ thuộc vào sự chú ý của người dùng, ở đây không có gì mới. Nếu bạn muốn một cái gì đó tự động hơn, hãy kiểm tra một câu trả lời cập nhật ở trên.
Ivan Kharlamov

2

Những gì như thế này?

#!/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
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.