本文目录导读:

我来介绍几种在Shell脚本中查找和去重重复文件的方法:
基于MD5校验的方法
#!/bin/bash
# 方法1:查找重复文件并显示
find . -type f -exec md5sum {} \; | sort | uniq -d -w 32
# 方法2:显示重复文件的分组
find . -type f -exec md5sum {} \; | sort | awk '{
if (seen[$1]) {
print "Duplicate:", $2
} else {
seen[$1] = $2
}
}'
# 方法3:完整的去重脚本
find_duplicates() {
local search_dir="${1:-.}"
echo "正在查找重复文件..."
find "$search_dir" -type f -exec md5sum {} \; |
sort |
awk '{
if (seen[$1]) {
print "DUPLICATE: " $2
duplicates[$1]++
} else {
seen[$1] = $2
}
}'
echo "统计重复文件数量..."
awk '{print $1}' | sort | uniq -c | sort -rn
}
保留一个副本删除其余
#!/bin/bash
# 保留第一个文件,删除其他重复文件
dedup_keep_first() {
local directory="${1:-.}"
declare -A file_hashes
find "$directory" -type f | while read -r file; do
hash=$(md5sum "$file" | cut -d' ' -f1)
if [[ -n "${file_hashes[$hash]}" ]]; then
echo "删除重复文件: $file"
rm "$file"
else
file_hashes[$hash]="$file"
fi
done
}
# 交互式去重(询问是否删除)
dedup_interactive() {
find . -type f -exec md5sum {} \; | sort | awk '
NR == 1 { first=$2; hash=$1 }
NR > 1 {
if ($1 == hash) {
printf "保留: %s\n删除: %s [y/N] ", first, $2
getline answer < "/dev/tty"
if (answer == "y" || answer == "Y") {
system("rm \"" $2 "\"")
print "已删除"
} else {
print "保留"
first=$2
}
} else {
first=$2
hash=$1
}
}'
}
使用shasum(更准确的校验)
#!/bin/bash
# 使用SHA256校验
find_duplicates_sha256() {
find . -type f -exec sha256sum {} \; | sort | uniq -d -w 64 | while read -r hash file; do
echo "重复文件: $file"
done
}
# 查找并移动到回收站
dedup_to_trash() {
local trash_dir="${HOME}/.trash"
mkdir -p "$trash_dir"
find . -type f -exec sha256sum {} \; | sort | awk '
{
if (seen[$1]) {
dest="'"$trash_dir"'" "/" $2
mkdir -p "$(dirname "$dest")"
system("mv \"" $2 "\" \"" dest "\"")
print "移动到回收站: " $2
} else {
seen[$1] = $2
}
}'
}
高级功能脚本
#!/bin/bash
# 完整的去重工具
dedup_tool() {
local search_dir="${1:-.}"
local action="${2:-list}" # list, delete, move, hardlink
local hash_cmd="${3:-md5sum}"
local temp_file=$(mktemp)
echo "扫描目录: $search_dir"
echo "使用算法: $hash_cmd"
echo "操作模式: $action"
# 生成文件哈希列表
find "$search_dir" -type f -exec "$hash_cmd" {} \; > "$temp_file"
# 根据模式处理
case "$action" in
list)
cat "$temp_file" | sort | awk '
NR == 1 { first=$2; hash=$1 }
NR > 1 {
if ($1 == hash) {
print first
print $2
} else {
first=$2
hash=$1
}
}' | sort -u
;;
delete)
cat "$temp_file" | sort | awk '
{
if (seen[$1]) {
print "删除: " $2
system("rm \"" $2 "\"")
} else {
seen[$1] = $2
}
}'
;;
move)
local backup_dir="${search_dir}/duplicates_backup"
mkdir -p "$backup_dir"
cat "$temp_file" | sort | awk -v backup="$backup_dir" '
{
if (seen[$1]) {
dir=backup "/" $2
system("mkdir -p \"$(dirname \"" dir "\")\"")
system("mv \"" $2 "\" \"" dir "\"")
print "移动: " $2
} else {
seen[$1] = $2
}
}'
;;
hardlink)
# 使用硬链接节省空间
cat "$temp_file" | sort | awk '
{
if (seen[$1]) {
system("ln -f \"" seen[$1] "\" \"" $2 "\"")
print "硬链接: " $2 " -> " seen[$1]
} else {
seen[$1] = $2
}
}'
;;
esac
rm -f "$temp_file"
}
# 使用方法
# dedup_tool "/path/to/dir" "list" "sha256sum"
# dedup_tool "/path/to/dir" "delete" "md5sum"
# dedup_tool "/path/to/dir" "hardlink" "sha1sum"
性能优化版本(适合大文件)
#!/bin/bash
# 快速去重(先按文件大小过滤)
dedup_fast() {
local directory="${1:-.}"
echo "步骤1: 按文件大小分组..."
find "$directory" -type f -exec stat -f"%z %N" {} \; | sort -n | awk '
{
if (size != $1) {
size=$1
files=$2
} else {
print files
print $2
}
}' | while read -r file1 && read -r file2; do
# 只对大小相同的文件进行哈希比较
if [ -f "$file1" ] && [ -f "$file2" ]; then
if cmp -s "$file1" "$file2"; then
echo "重复文件: $file1 和 $file2"
fi
fi
done
}
统计报告版本
#!/bin/bash
# 生成重复文件报告
report_duplicates() {
local directory="${1:-.}"
local report_file="duplicates_report_$(date +%Y%m%d).txt"
{
echo "重复文件报告"
echo "生成时间: $(date)"
echo "扫描目录: $directory"
echo "========================================"
echo ""
find "$directory" -type f -exec sha256sum {} \; | sort | awk '
{
if (seen[$1]) {
if (!header_printed[$1]) {
print "哈希: " $1
print " 原始: " seen[$1]
header_printed[$1] = 1
}
print " 重复: " $2
count[$1]++
} else {
seen[$1] = $2
}
}
END {
print ""
print "统计信息:"
for (hash in count) {
print " " count[hash] "个重复文件 (哈希: " substr(hash,1,8) "...)"
}
}'
} > "$report_file"
echo "报告已保存到: $report_file"
wc -l "$report_file"
}
使用建议
- 先测试:在正式删除前先用
list模式查看结果 - 备份重要文件:使用
move模式移动重复文件 - 大文件处理:先按大小过滤,再比较校验码
- 软链接保留:如需保留软链接,使用
-L参数 - 空格处理:确保文件名含空格时正确引用
- 权限问题:可能需要
sudo权限访问某些文件
这些脚本可以根据实际需求进行调整和组合使用。