Linux下查找含40位十六进制字符的文件(find及shell用法咨询)
一、你的find命令失效的原因
你用find . -regextype grep -regex '[0-9A-F]\{40\}'没效果,核心原因是find的-regex选项默认匹配的是整个文件路径,而不是单独的文件名。
举个例子:假设当前目录下有个符合要求的文件1A2B3C...(共40位),它的完整路径是./1A2B3C...,长度是41(加上开头的./)。你的正则[0-9A-F]\{40\}只能匹配恰好40个字符的字符串,自然匹配不上带路径前缀的完整路径,所以找不到文件。
二、正确的find命令写法
有两种常用的解决思路:
1. 调整正则匹配完整路径
让正则匹配路径的最后一段是40位十六进制字符,也就是在正则前加上匹配任意路径前缀的表达式:
find . -regextype grep -regex '.*/[0-9A-F]\{40\}'
这里的.*/会匹配从当前目录到目标文件的所有路径前缀,后面的[0-9A-F]\{40\}精准匹配文件名部分。如果需要忽略大小写(比如文件名里有小写的a-f),可以换成-iregex选项。
2. 单独提取文件名再匹配
用find的-printf选项只输出文件名,再通过管道传给grep过滤,这样就不用考虑路径前缀的问题:
find . -type f -printf '%f\n' | grep '[0-9A-F]\{40\}'
加上-type f可以只找文件(排除目录),如果需要包含目录可以去掉这个选项。
三、附加问题:用shell正则/通配符实现需求
你尝试的ls -l [0-9A-F]{40}不生效,是因为bash的大括号{}在这里不是正则次数限定符——bash的大括号是扩展语法(比如{1..5}生成1到5的序列),不是正则的重复匹配。要实现这个需求,可以分两种场景:
1. 用shell通配符(globbing)结合筛选
首先开启bash的extglob扩展(支持更复杂的通配符):
shopt -s extglob
然后先列出所有仅由十六进制字符组成的文件/目录,再用awk筛选长度恰好为40的:
ls -d +([0-9A-F]) | awk 'length($0) == 40'
这里的+([0-9A-F])是extglob语法,匹配一个或多个十六进制字符;awk 'length($0)==40'则只保留长度为40的文件名。
2. 用grep配合ls输出
直接用ls列出内容,再通过grep匹配文件名部分(注意ls -l的输出结构,最后一列是文件名):
ls -l | grep -E '[0-9A-F]{40}$'
这里的-E启用扩展正则,$确保匹配的是行尾(也就是文件名的结尾),这样就能精准匹配文件名是40位十六进制的条目。如果需要排除目录,可以再加个过滤:
ls -l | grep -E '^-.*[0-9A-F]{40}$'
^-表示行首是-,对应普通文件的权限位开头。
内容的提问来源于stack exchange,提问作者Doron Behar

