파일 경로가 주어지면 해당 파일의 모든 복사본을 찾는 방법은 무엇입니까?

파일 경로가 주어지면 해당 파일의 모든 복사본을 찾는 방법은 무엇입니까?

rdfind나는 또는 같은 프로그램을 알고 있습니다 fdupes. 유사하지만 더 복잡한 문제를 해결합니다.

파일 경로와 디렉토리가 주어지면 디렉토리를 재귀적으로 검색하여 다른 이름, 권한 또는 소유권에 관계없이 파일의 모든 복사본을 찾고 싶습니다.

rdfind needle.file haystack/예를 들어, 이 작업 을 수행 needle.file하면 haystack.

출력을 필터링할 수 있지만 출력이 rdfind크면 haystack/불필요한 작업이 많이 발생합니다.

scripts/cron-job에서 사용할 계획이므로 명령줄 응용 프로그램이 있어야 합니다.

답변1

간단한 방법:

  • 대상 파일을 가져와서 md5sum변수에 저장
  • 파일 크기를 가져와서 변수에 저장합니다.
  • 동일한 크기의 모든 파일에서 find실행md5sum
  • grepfind목표 MD5 해시 값의 출력
target_hash=$(md5sum needle.file | awk '{ print $1 }')
target_size=$(du -b needle.file | awk '{ print $1 }')
find haystack/ -type f -size "$target_size"c -exec md5sum {} \; | grep $target_hash

답변2

Czkawka(플랫 휠그리고GitHub).

이것은 체크섬과 같은 고급 기능을 갖춘 훌륭한 GUI 도구입니다.

답변3

파일 수가 많지 않은 경우(예: 1000개 미만) bash 스크립트가 적합할 수 있습니다. 그렇지 않으면 루프( md5sum, )에서 바이너리를 실행하면 상당한 오버헤드가 발생합니다.stat

1G 크기의 파일 1000개가 있으면 바이너리 로딩 오버헤드가 상대적으로 작기 때문에 파일 크기가 중요합니다. 그러나 1K 크기의 파일이 1000,000개 있다면 이야기가 달라집니다.

변형 번호 1

md5sum용법.

find_dups_by_md5.sh

#!/bin/bash

get_size() {
    stat -c"%s" "$1"
}

get_hash() {
    md5sum "$1" | cut -d' ' -f1 
}

needle=$1
needle_size=$(get_size "$needle")
needle_hash=$(get_hash "$needle")

shopt -s globstar
GLOBIGNORE=$needle

for f in **; do
    cur_file_size=$(get_size "$f")
    if [[ "$needle_size" != "$cur_file_size" ]]; then
        continue
    fi  

    cur_file_hash=$(get_hash "$f")
    if [[ "$needle_hash" != "$cur_file_hash" ]]; then
        continue
    fi  

    echo -e "duplicate:\t${f}"
done

변종 2

cmp용법.

간단한 바이트별 비교가 훨씬 더 좋습니다. 코드는 적고 결과는 동일하며 조금 더 빠릅니다. 여기서 해시는 한 번만 사용되므로 해시 계산이 중복됩니다. 각 파일에 대해 md5sum(needle 파일 포함) 해시를 수행하고 md5sum정의된 대로 전체 파일을 처리합니다. 따라서 100개의 1GB 파일이 있는 경우 md5sum파일이 원래 다른 킬로바이트였더라도 100G가 모두 처리됩니다.

따라서 각 파일을 대상과 단일 비교하면 바이트별 비교 시간은 최악의 경우 동일하거나(모든 파일의 내용이 동일함) 파일의 내용이 다른 경우(md5 가정 하에 더 빨라집니다. ha 계산 시간은 바이트별 비교와 동일합니다).

find_dups_by_cmp.sh

#!/bin/bash

get_size() {
    stat -c"%s" "$1"
}

needle=$1
needle_size=$(get_size "$needle")

shopt -s globstar
GLOBIGNORE=$needle

for f in **; do
    cur_file_size=$(get_size "$f")
    if [[ "$needle_size" != "$cur_file_size" ]]; then
        continue
    fi  

    if ! cmp -s "$needle" "$f"; then
        continue
    fi  

    echo -e "duplicate:\t${f}"
done

시험

테스트 파일 생성

###Generate test files
echo_random_bytes () {
    openssl rand -base64 100000;
}

shopt -s globstar

mkdir -p {a..d}/{e..g}/{m..o}

#Fill directories by some files with random content
touch {a..d}/{e..g}/{m..o}/file_{1..5}.txt
for f in **; do
    [ -f "$f" ] && echo_random_bytes > "$f"
done

#Creation of duplicates
same_string=$(echo_random_bytes)

touch {a..d}/{e..g}/m/dup_file.txt
for f in {a..d}/{e..g}/m/dup_file.txt; do
    echo "$same_string" > "$f"
done

#Target file creation
echo "$same_string" > needle_file.txt

중복 검색

$ ./find_dups_by_md5.sh needle_file.txt
duplicate:  a/e/m/dup_file.txt
duplicate:  a/f/m/dup_file.txt
duplicate:  a/g/m/dup_file.txt
duplicate:  b/e/m/dup_file.txt
duplicate:  b/f/m/dup_file.txt
duplicate:  b/g/m/dup_file.txt
duplicate:  c/e/m/dup_file.txt
duplicate:  c/f/m/dup_file.txt
duplicate:  c/g/m/dup_file.txt
duplicate:  d/e/m/dup_file.txt
duplicate:  d/f/m/dup_file.txt
duplicate:  d/g/m/dup_file.txt

성능 비교

$ time ./find_dups_by_md5.sh needle_file.txt > /dev/null

real    0m0,761s
user    0m0,809s
sys 0m0,169s

$ time ./find_dups_by_cmp.sh needle_file.txt > /dev/null

real    0m0,645s
user    0m0,526s
sys 0m0,162s

답변4

Panki의 답변에 따르면 호출 횟수가 줄어들어 md5sum확인할 파일이 수천 개 있는 경우 성능이 향상됩니다.

target_hash="$(md5sum needle.file | awk '{ print $1 }')"
target_size="$(du -b needle.file | awk '{ print $1 }')"
find haystack/ -type f -size "$target_size"c -print0 | xargs -0 md5sum | grep "^$target_hash"

참고: 원본 파일과 마찬가지로 파일 이름에 줄 바꿈이 포함되어 있으면 표시 문제가 발생할 수 있습니다.

관련 정보