มีวิธีการลบรายการที่ซ้ำกันที่ละเอียดกว่า fdupes -rdN หรือไม่?


22

เมื่อเร็ว ๆ นี้ฉันมีความจำเป็นต้องลบข้อมูลซ้ำซ้อนมากมาย ฉันกำลังรวมระบบไฟล์สามหรือสี่ระบบและฉันต้องการพื้นที่ที่จะใช้อย่างประหยัด ตอนแรกfdupesดูเหมือนว่ามันจะเป็นเครื่องมือที่ดีที่สุดสำหรับงาน แต่ฉันก็เริ่มมีข้อ จำกัด มากขึ้น

fdupes -rdN somedirectory/พิจารณาคำสั่ง สิ่งนี้ทำให้แฮชของไฟล์ทั้งหมดในไดเรกทอรีย่อยของไดเรกทอรีหนึ่ง ๆ

และเมื่อเกิดการซ้ำซ้อนมันจะลบมันออกไปดังนั้นมันจึงมีเพียงสำเนาเดียวของทุกสิ่ง

แต่ถ้าฉันต้องการเก็บไว้somedirectory/subdirectory1/somefileและในความเป็นจริงมีสี่รายการที่ซ้ำกันและโปรแกรมพบหนึ่งในรายการที่ซ้ำกันก่อน จากนั้นมันจะลบsomedirectory/subdirectory1/somefileซึ่งฉันไม่ต้องการ

ฉันต้องการที่จะสามารถระบุอย่างใดที่ซ้ำกันเพื่อให้ จนถึงตอนนี้ไม่มีโปรแกรมมาตรฐานสำหรับจัดการกับรายการที่ซ้ำกัน (ดัฟฟ์, FSLint) ที่ดูเหมือนว่าจะอนุญาตการทำงานอัตโนมัติของพฤติกรรมดังกล่าว ฉันไม่ต้องการม้วนตัวเองดังนั้นฉันจึงถามคำถามนี้

ฉันต้องการที่จะสามารถเขียนสิ่งที่ชอบ

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

ฉันกำลังมองหาสิ่งเดียวกันและฉันพบsuperuser.com/a/561207/218922
alexis

คำตอบ:


5

ในขณะที่ฟังก์ชั่นที่คุณค้นหาไม่มีในสต็อกfdupesแต่ฉันแยกfdupes (เรียกว่าส้อมของฉันjdupes)และเพิ่มคุณสมบัติบางอย่างที่สามารถแก้ปัญหานี้ได้ในบางสถานการณ์ ยกตัวอย่างเช่นในกรณีที่ระบุไว้ที่คุณต้องการเก็บsomedirectory/subdirectory1/somefileเมื่อซ้ำกันโดยอัตโนมัติลบ (คนdและNสวิทช์ร่วมกัน) และไม่มีแฟ้มที่แยกต่างหากทันทีใต้somedirectory, jdupesสามารถเลี้ยงแต่ละเส้นทางไดเรกทอรีย่อยทันทีที่มีsubdirectory1ครั้งแรกและ-Oสวิทช์ (ซึ่งเรียงลำดับไฟล์ตามคำสั่ง สั่งซื้อพารามิเตอร์บรรทัดแรก):

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

สิ่งนี้จะลบทั้งหมดโดยอัตโนมัติ แต่ไฟล์เดียวในชุดที่ซ้ำกันและจะรับประกันว่าหากชุดนั้นมีไฟล์อยู่ในsomedirectory/subdirectory1นั้นจะเป็นไฟล์แรกดังนั้นจึงกลายเป็นไฟล์ที่สงวนไว้ในชุดโดยอัตโนมัติ ยังคงมีข้อ จำกัด ที่ชัดเจนสำหรับวิธีนี้เช่นความจริงที่ว่าการทำสำเนาในsomedirectory/subdirectory1อาจถูกเก็บรักษาไว้แทนที่จะเป็นวิธีที่คุณต้องการเก็บไว้ แต่ในกรณีจำนวนมากเช่นคุณjdupesตัวเลือกลำดับพารามิเตอร์เป็นวิธีแก้ปัญหานั้นดีพอ

ในอนาคตอันใกล้นี้ฉันวางแผนที่จะเพิ่มระบบการกรองเพื่อjdupesให้สามารถควบคุมการรวม / แยกไฟล์จำนวนมากการสงวนไว้สำหรับ-Nการกระทำและการใช้งานของ "ตัวกรองสแต็ค" บนพื้นฐานแบบโกลบอลหรือต่อพารามิเตอร์ คุณลักษณะนี้จำเป็นอย่างมาก ฉันนึกภาพบางอย่างเช่นนี้กับ "การลบซ้ำอัตโนมัติที่ไม่เป็นศูนย์ซ้ำซ้ำ แต่จะรักษาsomedirectory/subdirectory1/somefileตามที่เป็นอยู่เสมอ":

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


4

สิ่งที่เกี่ยวกับ hardlinking ไฟล์ที่ซ้ำกันเข้าด้วยกัน? ด้วยวิธีนี้พื้นที่ใช้เพียงครั้งเดียว แต่ยังคงมีอยู่ในทุกเส้นทาง สิ่งที่จับได้คือไฟล์ hardlinked ควรได้รับการแก้ไข (ควรแก้ไขเฉพาะการลบไฟล์และสร้างใหม่ด้วยเนื้อหาใหม่) วิธีอื่นคือการเชื่อมโยงไฟล์เข้าด้วยกันแม้ว่าคุณจะมีปัญหาเดียวกันในการตัดสินใจว่าไฟล์ "หลัก" คืออะไร สิ่งนี้สามารถทำได้ด้วยสคริปต์ต่อไปนี้ (แม้ว่าโปรดทราบว่านี่ไม่ได้จัดการชื่อไฟล์ที่มีช่องว่าง)

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

1
การใช้jdupesแทนที่จะเป็นfdupesคุณก็สามารถทำได้jdupes -nrL somedirectory/อย่างรวดเร็วยิ่งขึ้น
โจดี้ลีบรูชอน

1
พิมพ์ผิดในลิงก์ไปยัง jdupes ลิงค์สะดวกซื้อ: github.com/jbruchon/jdupes
Royce Williams

4

ฉันไม่เห็นอันนี้ที่ไหนเลย: พูดในสิ่งที่คุณต้องการได้ คุณมี / mnt / folder-tree-1 / mnt / folder-tree-2 คุณไม่ต้องการลบทุกการล่อลวง แต่ถ้าไฟล์มีอยู่ใน tree-2 และไฟล์ที่เหมือนกันมีอยู่ใน tree-1 ที่มีพา ธ และชื่อเหมือนกันให้ลบออกจาก tree-2

คำเตือน: เรื่องนี้ค่อนข้างสั้นและหากคุณพยายามคัดลอกนี่ด้วยทักษะเชลล์ จำกัด ให้ระวัง

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

หรือทั้งหมดในบรรทัดเดียว:

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

หลังจากนั้นตรวจสอบและดำเนินการ rm-v2-dupes.sh


4

ฉันมีคำถามเดียวกัน หากคุณมีหลายรายการที่ซ้ำกันfdupes /my/directory/ -rdNเก็บไฟล์ที่มีวันที่แก้ไขที่เก่าที่สุดหรือถ้าหลายไฟล์มีวันที่แก้ไขเหมือนกันแล้วคนที่พบก่อน

หากวันที่แก้ไขไม่สำคัญสำหรับคุณคุณสามารถtouchเก็บไฟล์ในไดเรกทอรีที่คุณต้องการเก็บไว้ได้ หากคุณเลือกtouchวันที่และเวลาปัจจุบันพวกเขา fdupes -rdNiจะเก็บวันที่ปัจจุบันไว้ หรือคุณสามารถtouchเก็บไฟล์ด้วยวันที่ก่อนหน้าวันที่ที่คุณต้องการลบและใช้งานได้fdupes -rdNตามปกติ

หากคุณต้องการเก็บวันที่แก้ไขคุณจะต้องใช้วิธีอื่นอย่างใดอย่างหนึ่ง


3

เพียงแค่เพิ่มความบิดให้กับคำตอบก่อนหน้า ฉันใช้รหัสต่อไปนี้หลายครั้งปรับเปลี่ยนคำตอบก่อนหน้าเล็กน้อยด้วยวิธีง่าย ๆ| grepในการแยกโฟลเดอร์ที่ฉันต้องการลบออก

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

อีกครั้งนี้จะสร้างไฟล์ sh เพื่อลบไฟล์ทั้งหมดในรายการไม่มีบรรทัดที่มีความคิดเห็น แน่นอนคุณยังคงสามารถแก้ไขไฟล์เพื่อคอมเม้นท์บรรทัด / ไฟล์เฉพาะที่คุณต้องการเก็บไว้

คำแนะนำอีกข้อสำหรับไดเรกทอรีขนาดใหญ่คือการเรียกใช้ fdupes ไปยังไฟล์ txt จากนั้นทำการทดสอบด้วย| grepและ| sedจนกว่าฉันจะได้ผลลัพธ์ตามที่ต้องการ

`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เพื่อสร้างไฟล์เชลล์ที่จะมีคำสั่งใส่ความคิดเห็นเพื่อลบไฟล์ที่ซ้ำกันของคุณแต่ละไฟล์:

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

ผลลัพท์ที่ได้ remove-duplicate-files.shไฟล์ที่เราเพิ่งสร้างจะมีการคอมเม้นท์แต่ละบรรทัด ยกเลิกการคอมเม้นไฟล์ที่คุณต้องการลบ sh remove-duplicate-files.shจากนั้นเรียก Voila!

UPDATE

ถ้าคุณไม่ต้องการลบไฟล์ในบางไดเรกทอรีมันก็ง่ายเหมือนนี้ :

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

ที่ไหน 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)

remove-duplicate-files-keep-protected.shไฟล์ผลลัพธ์ที่เราเพิ่งสร้างขึ้นจะมีไฟล์ทั้งหมดจากไดเรกทอรีที่ได้รับการป้องกันแสดงความคิดเห็น เปิดไฟล์นี้ในโปรแกรมแก้ไขข้อความที่คุณชื่นชอบตรวจสอบว่าทุกอย่างเรียบร้อย จากนั้นเรียกใช้ Voila (sic)!


ฉันคิดถึงสิ่งนี้ แต่มันไม่อัตโนมัติพอ อย่างโง่เขลาฉันทำให้ข้อมูลสูญหายด้วยวิธีนี้เมื่อจัดการกับข้อมูลที่ซ้ำกันที่เว้นระยะในระบบไฟล์หลาย ๆ ระบบ ... ไม่มีวิธีกำหนดลำดับความสำคัญเนื่องจากเอาต์พุตของ fdupes โดยพื้นฐานแล้วฉันจะต้องลากไฟล์ 10,000 ไฟล์ด้วยมือเพื่อป้องกันการสูญหายของข้อมูล ... ดังนั้นไม่ต้องขอบคุณ ... อันที่จริงการสูญเสียข้อมูลนั้นเป็นเหตุผลที่ฉันถามคำถามนี้
ixtmixilix

@ixtmixilix ดีวิธีการด้วยตนเองขึ้นอยู่กับความสนใจของผู้ใช้นี่คือไม่มีอะไรใหม่ หากคุณต้องการสิ่งที่เป็นอัตโนมัติมากขึ้นให้ชำระเงินคำตอบที่อัปเดตข้างต้น
Ivan Kharlamov

2

แล้วเรื่องแบบนี้ล่ะ?

#!/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
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.