rdfind
나는 또는 같은 프로그램을 알고 있습니다 fdupes
. 유사하지만 더 복잡한 문제를 해결합니다.
파일 경로와 디렉토리가 주어지면 디렉토리를 재귀적으로 검색하여 다른 이름, 권한 또는 소유권에 관계없이 파일의 모든 복사본을 찾고 싶습니다.
rdfind needle.file haystack/
예를 들어, 이 작업 을 수행 needle.file
하면 haystack
.
출력을 필터링할 수 있지만 출력이 rdfind
크면 haystack/
불필요한 작업이 많이 발생합니다.
scripts/cron-job에서 사용할 계획이므로 명령줄 응용 프로그램이 있어야 합니다.
답변1
간단한 방법:
- 대상 파일을 가져와서
md5sum
변수에 저장 - 파일 크기를 가져와서 변수에 저장합니다.
- 동일한 크기의 모든 파일에서
find
실행md5sum
grep
find
목표 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
답변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"
참고: 원본 파일과 마찬가지로 파일 이름에 줄 바꿈이 포함되어 있으면 표시 문제가 발생할 수 있습니다.