如何用Bash的Grep正则匹配仅含单个顶级域名的邮箱
匹配仅含单个顶级域名的邮箱
问题根源
你使用的grep -E采用POSIX扩展正则标准,不支持负前瞻这类Perl兼容正则(PCRE)特性;而添加$的正则仅能匹配行尾的邮箱,若日志中邮箱后还有其他内容就无法命中。
解决方案1:使用grep的PCRE模式(推荐)
大部分GNU grep支持-P选项启用PCRE,直接复用你原本的正则即可生效:
grep -P -o '[A-Za-z0-9.]+@[A-Za-z0-9-]+\.[A-Za-z]{2,}(?!\.[A-Za-z])' log.txt > mails.txt
-P:启用Perl兼容正则,让负前瞻(?!\.[A-Za-z])生效,确保顶级域名后不会出现.字母的多级域名结构-o:仅输出匹配到的邮箱部分,无需依赖行尾位置
解决方案2:无PCRE支持时的替代方案(awk实现)
如果你的系统不支持grep -P(如部分BSD系统),可以用awk先匹配所有基础格式的邮箱,再过滤掉多级顶级域名的情况:
awk '{ while (match($0, /[A-Za-z0-9.]+@[A-Za-z0-9-]+\.[A-Za-z]{2,}/, mail_arr)) { candidate = mail_arr[0] # 排除末尾包含两个及以上顶级域名段的邮箱 if (candidate !~ /\.[A-Za-z]+\.[A-Za-z]+$/) { print candidate } # 截断字符串,继续匹配后续内容 $0 = substr($0, RSTART + RLENGTH) } }' log.txt > mails.txt
解决方案3:纯POSIX扩展正则实现
也可以用扩展正则结合sed处理,避开PCRE特性:
grep -E -o '[A-Za-z0-9.]+@[A-Za-z0-9-]+\.[A-Za-z]{2,}([^A-Za-z.]|$)' log.txt | sed 's/[^A-Za-z0-9.@-]$//'
- 正则部分匹配邮箱后接非字母点的字符或行尾
- 用
sed移除邮箱末尾可能附带的非邮箱字符(如空格、标点)
内容的提问来源于stack exchange,提问作者Y2theZ
相关产品推荐
相关产品推荐

