fdupes -rdN보다 더 세련된 복제본을 삭제하는 방법이 있습니까?


22

최근에 많은 사본을 삭제해야합니다. 3 ~ 4 개의 파일 시스템을 병합하고 있으며 공간을 경제적으로 사용하기를 원합니다. 처음에는 fdupes그것이 작업에 가장 적합한 도구 인 것처럼 보였지만 점점 한계에 부딪 치고 있습니다.

명령을 고려하십시오 fdupes -rdN somedirectory/. 이것은 일부 디렉토리의 서브 디렉토리에있는 모든 파일을 해시합니다.

그리고 중복이 발견되면 모든 사본이 하나만 있도록 삭제합니다.

그러나 보관 somedirectory/subdirectory1/somefile하고 싶은데 실제로 4 개의 복제본이 있고 프로그램이 복제본 중 하나를 먼저 만나면 어떻게해야합니까? 그런 다음 somedirectory/subdirectory1/somefile원하지 않는를 삭제 합니다.

어떻게 든 복제 할 것을 지정할 수 있기를 원합니다. 그리고 지금까지 복제를 처리하기위한 표준 프로그램 (더프, FSLint)은 그러한 종류의 동작을 자동화 할 수있는 것으로 보이지 않습니다. 나는 내 자신의 롤을 원하지 않기 때문에이 질문을하는 이유입니다.

나는 같은 것을 쓸 수 있기를 원합니다

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

나는 같은 것을 찾고
있었고이

답변:


5

당신이 찾는 기능의 재고가 사용할 수없는 동안 fdupes, 나는 포크 fdupes (내 포크를 호출 jdupes) 및 특정 상황에서이 문제를 해결할 수있는 몇 가지 기능을 추가했습니다. 예를 들어, 명시된 경우에 당신이 유지하고자하는 경우 somedirectory/subdirectory1/somefile자동 삭제 중복합니다 (시 dN스위치를 함께)과 별도의 파일이 바로 아래가없는 somedirectory, jdupes각 즉시 하위 디렉토리 경로를 공급 할 수있다 subdirectory1, 제 1 및 -O명령으로 파일을 정렬하는 (스위치 -line 매개 변수 순서 먼저) :

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

이렇게하면 복제 세트에서 하나의 파일을 제외한 모든 파일이 자동으로 삭제되며 세트에 파일이 포함 된 파일 somedirectory/subdirectory1이 첫 번째 파일 이므로 자동으로 세트의 보존 된 파일이됩니다. 이 접근 방식에는 유지하려는 복제본 somedirectory/subdirectory1대신 다른 복제본 이 보존 될 수 있다는 점과 같이 여전히 눈에 띄는 한계가 있지만 jdupes매개 변수 순서 옵션은 해결 방법으로 충분합니다.

가까운 장래에, 필자 jdupes는 파일 포함 / 제외, -N동작 보존 및 이러한 "필터 스택"의 적용을 글로벌 또는 매개 변수별로 엄청나게 제어 할 수 있는 필터링 시스템을 추가 할 계획 입니다 . 이 기능은 절실히 필요합니다. 나는 "0이 아닌 중복을 재귀 적으로 자동 삭제하지만 항상 그대로 유지합니다"와 같은 것을 상상합니다 somedirectory/subdirectory1/somefile.

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


4

중복 파일을 하드 링크로 연결하는 것은 어떻습니까? 그렇게하면 공간은 한 번만 사용되지만 여전히 모든 경로에 존재합니다. 이 문제는 하드 링크 된 파일을 수정해야합니다 (파일을 삭제하고 새 내용으로 다시 작성하는 것만 수정해야 함). "기본"파일을 결정하는 것과 동일한 문제가 있지만 다른 방법은 파일을 서로 연결하는 것입니다. 이것은 다음 스크립트로 수행 할 수 있습니다 (공백이 포함 된 파일 이름은 처리하지 않습니다).

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/.
Jody Lee Bruchon

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 파일이 작성됩니다. 물론 파일을 편집하여 보관하려는 특정 행 / 파일을 주석 처리 할 수 ​​있습니다.

큰 디렉토리에 대한 또 다른 힌트는, TXT 파일에 fdupes을 실행 실험하는 것입니다 | 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. 짜잔!

최신 정보

특정 디렉토리에서만 파일을 삭제하지 않으려면 다음과 같이 간단합니다 .

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방금 생성 한 결과 파일에는 보호 된 디렉토리의 모든 파일이 주석 처리됩니다. 자주 사용하는 텍스트 편집기에서이 파일을 열고 모든 것이 정상인지 확인하십시오. 그런 다음 실행하십시오. 짜잔!


나는 이것을 생각했지만 충분히 자동화되지 않았습니다. 어리석게도, 여러 파일 시스템에 걸쳐있는 중복을 처리 할 때이 방법으로 데이터 손실이 발생했습니다 ... fdupes의 출력을 고려하여 우선 순위를 할당 할 방법이 없습니다. 기본적으로 나는 데이터 손실을 막기 위해 손으로 10000 개의 파일을 트롤해야했습니다. 그래서 고맙습니다 ... 사실, 데이터 손실은 내가이 질문을 한 이유입니다.
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.