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

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

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

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

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

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

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

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



답변

당신이 찾는 기능의 재고가 사용할 수없는 동안 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/


답변

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

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


답변

나는 다른 곳에서는 이것을 보지 못했습니다. 당신이 원하는 것이 이것이라고 말하십시오. / 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를 검사하고 실행하십시오.


답변

나는 같은 질문을했다. 중복이 많은 경우 fdupes /my/directory/ -rdN파일을 가장 오래된 수정 날짜로 유지하거나 여러 파일의 수정 날짜가 같은 경우 먼저 찾은 파일이 있습니다.

수정 날짜가 중요하지 않은 경우 touch보관하려는 디렉토리의 파일 을 사용할 수 있습니다 . touch현재 날짜와 시간으로 선택 하면 현재 날짜와 시간을
fdupes -rdNi유지합니다. 또는 touch삭제하려는 파일보다 빠른 날짜로 파일을 보관 fdupes -rdN하고 정상적으로 사용할 수 있습니다 .

수정 날짜를 유지해야하는 경우 다른 방법 중 하나를 사용해야합니다.


답변

이전 답변에 비틀기를 추가하십시오. 다음 코드를 여러 번 사용하여 | 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`


답변

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


답변

이런 건 어때?

#!/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