如何从任意深度含横杠的子域名列表中提取以.分隔的末尾两级主域名
问题描述
现有一份存储子域名的列表文件,需要提取每行中以.为分隔符、从行尾开始计数的最后两段内容作为主域名,示例如下:
blog.clova.line.me
提取结果为:
line.me
初期尝试使用cut -d "." -f "2-3"命令剥离子域名前缀,但该命令仅对3层深度的子域名生效,当子域名深度大于等于4层时,会错误提取到中间段内容,示例:
clova.line.me -> line.me (结果正确) blog.clova.line.me -> clova.line (结果错误,预期为line.me)
之后尝试编写Shell脚本,逐行统计每行中.的数量,再根据数量调整cut命令的提取字段范围,脚本逻辑片段如下:
while read -r line; do for $(tr -cd "." << ${line} | wc -c) in i; if $i == 2; do cut -d "." -f "2-3"; else if $i == 3; do cut -d "." - f "3-4" and so-on
该方案需要逐行判断.的数量,执行效率很低。
后续尝试使用正则([a-z]*)\.([a-z]*)$进行匹配,但该正则无法适配域名段中包含特殊字符-的场景,会出现匹配错误,示例:
mobile.amazon-aws.com --> aws.com (预期结果为amazon-aws.com) branch.line-dev.net --> dev.net (预期结果为line-dev.net) git.line-apps-dev.net --> dev.net (预期结果为line-apps-dev.net) yugioh.line-games-de-dev.net --> dev.net (预期结果为line-games-de-dev.net)
需求汇总
- 支持提取深度3层及以上的子域名对应的主域名
- 域名段中可包含1个及以上的
-字符 - 目标:按照规则从子域名列表中正确提取主域名
解决方案
以下方案均为流处理模式,无需逐行写分支判断,处理大文件效率远高于逐行循环的脚本逻辑,且天然支持域名段包含-的场景:
方案1:awk实现(最简洁推荐)
直接按.分割行后取倒数第1、2个字段拼接即可,不限制域名总层数:
awk -F '.' '{print $(NF-1)"."$NF}' 子域名列表文件路径
参数说明:
-F '.':指定.为字段分隔符NF:内置变量,代表当前行的总字段数$(NF-1):倒数第二个字段,$NF:最后一个字段,中间拼接.即为目标主域名
方案2:grep+正则实现
修正原正则的匹配范围,不再限制仅匹配小写字母,改为匹配非.的任意字符,提取行尾最后两段即可:
grep -Eo '[^.]+\.[^.]+$' 子域名列表文件路径
参数说明:
-E:启用扩展正则-o:仅输出匹配到的内容,而非整行- 正则
[^.]+\.[^.]+$:匹配行尾位置的「1个及以上非.字符 + . + 1个及以上非.字符」,刚好对应最后两段域名
方案3:sed实现
通过正则替换,将整行前缀替换为空,仅保留最后两段域名:
sed -E 's/.*\.([^.]+\.[^.]+)$/\1/' 子域名列表文件路径
以上三种方案对所有测试用例都能返回正确结果,可根据自己熟悉的工具选择使用。
内容的提问来源于stack exchange,提问作者user19219732
相关产品推荐
相关产品推荐

