meta 目录里 1.2 万个文件改了名,我用 diff 对出了漏改的软链

上周整理 meta 目录,把一批按日期命名的快照目录统一改成带业务前缀的名字,大概 1.2 万个文件、300 多个目录,环境是 Debian 12,ext4,meta 版本在配置文件里记的是 2.4.7。改完跑校验脚本,有三条记录报找不到文件,但 ls 看路径明明在。

做法不复杂,先出一份改名前的清单,改名后再出一份,用路径做集合差,找出对不上的:

find /data/meta -type f -printf '%p\n' | sort > /tmp/before.txt
# 批量改名(这里用 rename,先 dry-run)
rename -n 's/^\/data\/meta\/snap-(\d{8})/\/data\/meta\/biz-$1/' /data/meta/snap-*/**/* 2>/dev/null
# 实际执行后
find /data/meta -type f -printf '%p\n' | sort > /tmp/after.txt
comm -23 /tmp/before.txt /tmp/after.txt | head -50

comm -23 出来的是「改名后找不到的旧路径」,本来预期只剩改名那一批,结果多出 17 条,全是软链。原因是我只对普通文件做了 -type f,软链被漏掉了;而且 rename 的表达式只匹配了目录名,没碰软链的 target。软链本身没坏,坏的是它的相对路径——目录层级变了,../snap-20240301/x 这种相对 target 就指偏了。

为什么用路径集合差而不是直接 diff -r:diff -r 会把内容变化也拉进来,1.2 万个文件跑一遍要几分钟,而集合差只关心「路径存在性」,几秒就完。代价是它看不见内容改动,也不检查软链目标是否可达,所以我又补了一步:

find /data/meta -type l -printf '%p -> %l\n' | while read -r line; do
  p=${line%% -> *}
  [ -e "$p" ] || echo "broken: $p"
done

这一步才把那 17 条断链揪出来。

失效的地方也说一下:-printf '%p\n' 在路径含换行时会断行,我的目录名干净所以没撞上;另外 comm 要求两边都排好序,我一开始用了 sort -u 去重,结果把同名不同层的文件也误判了。还有一次我图省事用 mv 批量改目录,中途 Ctrl-C,前后清单都对不上,只能从备份恢复。

你们在 meta 目录做批量改名时,是先跑 dry-run 再核软链,还是改完再补检查?

0
赞同度 100% · 0 条评论 · 3 阅读

0 条评论

支持 Markdown · 回复会实时推送给对方

还没有评论,写下第一条。