Linux find指定regextype为sed时正则负向断言不生效问题
匹配需求
匹配文件名中update字段后第二位数字不为0的.pt格式文件,匹配规则如下:
- 需命中:
./update110000.pt、./update170000.pt - 不命中:
./update100000.pt
问题复现
初始编写带负向断言的正则.*update[0-9](?!0)[0-9]{5}.pt,在通用正则测试环境下验证可正常命中目标文件,但在Linux系统执行find命令时无法得到预期结果:
- 第一次执行命令
find . -regextype sed -regex '.*update[0-9](?!0)[0-9]{5}.pt',无匹配结果 - 尝试对分组括号添加反斜杠转义,将正则修改为
.*update[0-9]\(?!0\)[0-9]{5}.pt后再次执行,依然匹配失效
当前已知可使用无断言正则.*update[0-9][1-9][0-9]{4}.pt实现需求,但需要明确find命令中(?!x)负向断言语法的正确使用方式。
原因说明与正确用法
失效核心原因
find命令指定-regextype sed时,使用的是POSIX基础正则(BRE)语法,该语法体系不支持零宽断言特性——你所用的(?!x)负向先行断言属于PCRE(Perl兼容正则)的独有语法,POSIX BRE/ERE系列正则均无法识别该结构,无论是否对括号转义都无法生效。
负向断言的正确使用方式
如果要在find的-regex参数中使用(?!x)负向断言,需切换正则类型为PCRE:
- 4.9及以上版本的GNU find原生支持pcre正则类型,直接指定
-regextype pcre即可,命令参考如下:
注意正则中匹配文件后缀的find . -regextype pcre -regex '.*update[0-9](?!0)[0-9]{5}\.pt'.需要转义为\.,避免.匹配任意字符导致误命中非.pt后缀的文件。 - 如果使用的find版本较低不支持pcre类型,可以通过管道交给grep的PCRE模式过滤,写法如下:
find . -name "*.pt" | grep -P 'update[0-9](?!0)[0-9]{5}\.pt$'
场景最优方案
你当前已经验证可用的.*update[0-9][1-9][0-9]{4}\.pt写法不需要依赖高阶正则特性,兼容所有正则引擎,匹配性能高于带断言的写法,在这个固定数字长度的匹配场景下是最稳妥的选择。
内容的提问来源于stack exchange,提问作者B.W. Zhang
相关产品推荐
相关产品推荐

