meta 目录里 700 个坏软链,我用 find -L 筛了两遍才敢动

meta 仓库的一个子目录,里面 2 万多个文件,软链大概 700 条。环境是 Ubuntu 22.04,coreutils 8.32,bash 5.1。某天做快照前想清理一下,先跑了一遍检测,发现 find . -type l 数出来 703 条,但 find -L . -type l 只有 41 条。差值不是误差,是判断标准不一样。

我的做法是先分两遍看,不动手:

# 第一遍:列出所有软链本身,不跟随
find meta -type l -printf '%p -> %l\n' > /tmp/links_all.txt

# 第二遍:跟随之后仍然断的
find -L meta -type l -print > /tmp/links_broken.txt

两遍结果对不上,说明有大量软链是“链到链”或者指向目录。接着确认目标是否存在,用 test -e 逐条判,比 -L 更贴近我关心的语义:

while IFS= read -r l; do
  [ -e "$l" ] || echo "$l"
done < <(find meta -type l) > /tmp/links_dead.txt

最后清点时,703 条里有 662 条是活链,41 条确实断了,其中 12 条断在二级链上——A 指向 B,B 指向一个已经不存在的 C。find -L 抓不到这种,因为它只跟一层。

为什么这么绕:-type l 在默认模式下看的是链接本身,-L 会改变整个遍历的语义,不只是对软链的判断。在 -L 下,目录软链会被当目录展开,-type l 就只剩“跟随失败”的链接。两者不是同一个问题,混用会把“活链”和“断链”的比例读反。代价是遍历变慢,-L 那遍在 2 万文件上多花了大概一倍时间,而且会跟着软链进到不该进的目录。

会失效的地方:循环软链会让 -L 直接报错退出,得加 -maxdepth 或者先单独排掉;指向文件系统外部的链接,-e 判断依赖挂载状态,换机器结果会变;还有权限,读不到的目录在 find 里是静默跳过的,断链数会偏少。我自己踩过的是最后一条,用普通用户跑出来 38 条,换 root 变成 41 条。

你们那边如果有二级链或者跨挂载点的软链,平时是用 -L 还是逐条 test -e 来判死的?

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

0 条评论

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

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