You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在哈希文件中精准匹配行尾指定文件名并提取对应哈希值

问题背景

我有两个文件:

  • $hashfile:每行存储哈希值和./相对路径文件名,二者以两个空格分隔
  • $badfiles:存储待在$hashfile中查询对应哈希值的./相对路径文件名

$hashfile示例片段如下:

c2c99b59f3303cafac85c2c6df6653cc  ./vm-mount.sh
058a8fb0b9366f248be32b7390e94595  ./Jerusalem_Canon EOS R5_20210601_031.jpg~
23eba1c54846de5244312047e2709f9a  ./rsync-back.sh
ff3f08f7bf45f8e9ef8b33192db3ce9a  ./vm-backup.sh
11e0d980f3b2219f65da97a0318e7dce  ./Jerusalem_Canon EOS R5_20210601_031.jpg
49fb1fb660dce09acd87861a228c899d  ./vm-test.sh

$badfiles存储的搜索模式示例如下:

./Jerusalem_Canon EOS R5_20210601_031.jpg
./file.txt

我的需求是在$hashfile中搜索$badfiles内的模式,将包含对应哈希值的匹配行写入第三个文件$new。

遇到的问题

我最初使用的命令如下:

grep -Ff "$badfiles" "$hashfile" > "$new"

但该命令会同时匹配到后缀带~的多余行,不符合要求:

058a8fb0b9366f248be32b7390e94595  ./Jerusalem_Canon EOS R5_20210601_031.jpg~
11e0d980f3b2219f65da97a0318e7dce  ./Jerusalem_Canon EOS R5_20210601_031.jpg

之后我给$badfiles的每行末尾添加了$,并将命令修改为:

grep -f "$badfiles" "$hashfile" > "$new"

该方案在小型测试场景下可用,但我有30万以上的文件名和哈希记录,且部分文件名包含"':,;<>()[]?等ext4、NTFS文件系统支持的特殊字符,正则匹配存在性能下降和匹配错误的风险,需要更稳妥的解决方案。

解决方案

grep没有提供在固定字符串搜索中加入行尾匹配的简单方案,最优解是使用awk实现:

awk 'NR == FNR {a[$0]; next}
{b=$0; sub(/^\S+\s+/, "", b)}
b in a' "$badfiles" "$hashfile" > "$new"

注意:$badfiles、$hashfile和$new均为存储文件名的变量。

命令说明

  • NR存储所有文件已读取的总行数,FNR存储当前文件已读取的行数。当awk读取$badfiles时,NR == FNR成立,将$badfiles的每一行内容存入数组a,next会阻止后续逻辑执行,直到$badfiles全部读取完成。
  • 读取$hashfile时,将当前行$0赋值给变量b,sub(/^\S+\s+/, "", b)会把变量b中开头的一个或多个非空白字符(哈希值)加一个或多个空白字符(分隔符)替换为空,此时变量b仅保留./路径/文件名。
  • 最后判断变量b是否存在于数组a中,若存在则将$hashfile的当前行写入$new文件。如果$badfiles的所有行都能在$hashfile中找到匹配项,$new将存储所有对应带哈希值的行。

简化版本

由于MD5哈希值长度固定为32位,加之后面的两个分隔空格共34个字符,因此awk语句可简化为:

awk 'NR == FNR {a[$0]; next}
{b=substr($0,35)}
b in a' "$badfiles" "$hashfile" > "$new"

substr()语句会从输入行$0的第35位(awk计数从1开始)开始截取子串赋值给b,相当于移除前34位的哈希值和分隔空格,类似bash中的子串提取${mystring:34}(bash子串计数从0开始)。

变体用法:排除指定文件

如果需要生成新哈希文件,排除$deletedfiles中列出的文件,可以使用以下命令:

awk 'NR == FNR {a[$0]; next}
{b=substr($0,35)}
!(b in a)' "$deletedfiles" "$hashfile" > "$new"

该命令会将$hashfile中路径不在$deletedfiles内的行写入$new。需要特别注意:如果$deletedfiles为空文件,$new也会为空,不符合预期的和$hashfile一致的结果。

该方案性能优异速度快,即使单哈希文件内有20-30万条文件名记录也可正常运行。


内容的提问来源于stack exchange,提问作者powerhouse

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.02 12:54:03