MD5校验对比脚本 📅 2026/7/24 6:05:03 始终显示统计摘要相同、不同、仅存在于 dir1、仅存在于 dir2加上-v选项时同时逐行显示每个文件的详细对比状态保留两种模式严格对比路径 MD5和仅内容对比忽略路径自动处理权限并给出友好的运行提示完整脚本compare_dirs_full.sh#!/bin/bashset-e# 显示帮助信息usage(){catEOF 用法:$0[选项] 目录1 目录2 比较两个目录下所有文件的 MD5 值递归处理子目录。 选项: -v, --verbose 显示每个文件的详细对比状态相同/不同/仅存在 -c, --content-only 只比较文件内容忽略文件名和路径 -h, --help 显示此帮助信息 无论是否使用 -v最后都会输出统计摘要。 示例:$0/root/var/www/html/upload /var/www/html/upload$0-v /root/var/www/html/upload /var/www/html/upload$0-c /root/var/www/html/upload /var/www/html/upload EOFexit1}# 默认参数verbosefalsecontent_onlyfalse# 解析选项OPTS$(getopt-ovch--longverbose,content-only,help-n$0--$)if[$?!0];thenusage;fievalset--$OPTSwhiletrue;docase$1in-v|--verbose)verbosetrue;shift;;-c|--content-only)content_onlytrue;shift;;-h|--help)usage;;--)shift;break;;*)break;;esacdone# 检查参数if[$#-ne2];thenecho错误需要两个目录作为参数usagefidir1$1dir2$2# 验证目录存在if[!-d$dir1];thenecho错误目录 $dir1 不存在exit1fiif[!-d$dir2];thenecho错误目录 $dir2 不存在exit1fi# 创建临时文件并设置清理tmp1$(mktemp)tmp2$(mktemp)traprm -f $tmp1 $tmp2EXIT# 生成 MD5 清单格式为 MD5 相对路径generate_list(){localdir$1localout$2(cd$dirfind.-typef-execmd5sum{}|seds|^\./|||sort-k2)$out}echo正在生成目录 $dir1 的 MD5 清单...generate_list$dir1$tmp1echo正在生成目录 $dir2 的 MD5 清单...generate_list$dir2$tmp2# ----- 仅比较内容忽略文件名 -----if[$content_onlytrue];thenecho--- 仅比较文件内容忽略文件名 ---# 提取 MD5 值排序后比较diff-u(awk{print $1}$tmp1|sort)(awk{print $1}$tmp2|sort)\|sed-e/^---/d-e/^\\\/d-e/^/d||true# 统计交集相同MD5、仅1、仅2comm-12(awk{print $1}$tmp1|sort)(awk{print $1}$tmp2|sort)|wc-l|xargsprintf\n相同内容文件数按MD5: %d\ncomm-23(awk{print $1}$tmp1|sort)(awk{print $1}$tmp2|sort)|wc-l|xargsprintf仅存在于 %s 的内容块数: %d\n$dir1comm-13(awk{print $1}$tmp1|sort)(awk{print $1}$tmp2|sort)|wc-l|xargsprintf仅存在于 %s 的内容块数: %d\n$dir2exit0fi# ----- 严格按路径对比 -----echo--- 对比目录结构和文件内容 ---# 使用 awk 进行逐行比较并收集统计信息awk-vverbose$verbose-vd1$dir1-vd2$dir2 function print_diff(path, md5a, md5b) { if (md5a md5b) print 相同: path else print 不同: path ( d1 : md5a , d2 : md5b ) } BEGIN { same0; diff0; only10; only20 } NRFNR { # 读取第一个清单 path $2; md5[path] $1; next } { # 读取第二个清单 path $2; if (path in md5) { if (md5[path] $1) { same; } else { diff; } if (verbose) print_diff(path, md5[path], $1); delete md5[path]; # 已匹配 } else { only2; if (verbose) print 仅在 d2 : path (MD5: $1 ) } } END { # 剩余在 md5 中的即为仅在 dir1 的文件 for (path in md5) { only1; if (verbose) print 仅在 d1 : path (MD5: md5[path] ) } # 始终输出统计摘要 printf \n 统计摘要 \n printf 相同文件数路径和内容均一致: %d\n, same printf 内容不同的文件数路径相同但MD5不同: %d\n, diff printf 仅存在于 %s 的文件数: %d\n, d1, only1 printf 仅存在于 %s 的文件数: %d\n, d2, only2 } $tmp1$tmp2exit0使用方法保存脚本并赋予执行权限sudovi/usr/local/bin/compare_dirs_full.sh# 或任意位置chmodx /usr/local/bin/compare_dirs_full.sh运行以您的目录为例仅显示统计摘要不输出每个文件的详情sudocompare_dirs_full.sh /root/var/www/html/upload /var/www/html/upload同时显示每个文件的详细状态 统计摘要sudocompare_dirs_full.sh-v/root/var/www/html/upload /var/www/html/upload只比较文件内容忽略路径sudocompare_dirs_full.sh-c/root/var/www/html/upload /var/www/html/upload输出示例带-v时部分输出正在生成目录 /root/var/www/html/upload 的 MD5 清单... 正在生成目录 /var/www/html/upload 的 MD5 清单... --- 对比目录结构和文件内容 --- 相同: images/logo.png 不同: config.ini ( /root/var/www/html/upload: d41d8cd98f00b204e9800998ecf8427e , /var/www/html/upload: 098f6bcd4621d373cade4e832627b4f6 ) 仅在 /var/www/html/upload: temp/cache.tmp (MD5: 5d41402abc4b2a76b9719d911017c592) 统计摘要 相同文件数路径和内容均一致: 120 内容不同的文件数路径相同但MD5不同: 3 仅存在于 /root/var/www/html/upload 的文件数: 5 仅存在于 /var/www/html/upload 的文件数: 2不加-v时只会输出摘要部分不会有详细列表。关键改进点始终输出统计摘要无论是否使用-vawk的END块都会打印四行统计。详细模式与摘要并存-v负责输出每行状态摘要始终在最后给出。清晰区分“路径相同但内容不同”和“仅存在某侧”便于定位问题。临时文件自动清理支持带空格的文件名。如果文件数量极大数十万级若目录包含海量文件生成 MD5 列表可能较慢。此时可以考虑使用parallel并行计算 MD5或改用md5deep工具可参考之前的建议。但本脚本对于常规规模几万文件完全够用。