在shell中提取域名的顶级主域名,核心思路是去掉子域名前缀、保留注册域名和顶级后缀,但盲目按“点”切分会踩坑,需要结合后缀规则或人工校验。 无论你是处理日志、分析URL,还是批量清洗域名列表,下面这些方法都能帮你快速搞定。
shell提取域名主域名,先搞懂“顶级主域名”是什么
所谓顶级主域名,指的是用户真正拥有控制权的那段域名,比如blog.example.co.uk,它的顶级后缀是co.uk,注册域名是example,所以完整主域名是example.co.uk,而www.example.co.uk里的www只是子域名。
主域名和后缀的边界怎么判断
这里的难点在于后缀列表,常见后缀如.com、.net、.org,直接取最后两段就行,但遇到.com.cn、.co.jp这样的“复合后缀”,必须把整个后缀当作一个整体,行业共识认为,真正的边界依据是ICANN维护的公共后缀列表(PSL),它列出了所有合法后缀,包括私有后缀如github.io,用它做判断最靠谱。
为什么不能单纯用“点”去切分
举个例子:api.somecompany.co.uk,如果你简单取最后两段,得到的是co.uk,这显然不是主域名,取最后三段,得到company.co.uk,这倒是正确了,可同样的规则放到api.somecompany.com上,取三段变成somecompany.com?不对,因为.com是单段后缀,三段会把api也带进去,按点数切”的规则在混合后缀环境下完全不可用。
另一个隐藏问题是“二级主域名”和“顶级主域名”的混淆,很多人把baidu.com叫顶级域名,严格说它属于一级注册域名,而www.baidu.com是子域名,在shell处理时,你需要明确目标:是去掉www,还是去掉所有子域名前缀,两者差异很大。
shell提取域名主域名的常用命令对比
如果你只需要处理少量数据,或者环境里没有Python、Node,纯shell命令速度最快,下面直接上实操。
用sed和awk做简单提取
对于单段后缀的域名(.com、.cn、.org),用awk按点拆分后取倒数第二段加后缀:
echo "img.test.example.com" | awk -F. '{if (NF>=2) print $(NF-1)"."$NF}'
输出是example.com,注意,这个命令没有过滤www,如果你只想去掉www,用sed 's/^www.//'先清洗。
对于已知的复合后缀(.com.cn、
.co.uk),手动列出规则:
echo "api.example.co.uk" | sed -E 's/^..(example.co.uk)$/1/'
这种方式死板但有效,当你处理的域名后缀种类有限,比如只针对国内站点,用awk加正则也能凑合:
echo "mp.weixin.qq.com" | sed -E 's/^[^.]+.([^.]+.[^.]+)$/1/'
这里[^.]+匹配任意一级子域,但遇到com.cn就出错,原因前面说过了。
用Python还是shell?两者取舍
行业内更推荐在条件允许时用Python的tldextract库,它能解析PSL并准确返回主域名,虽然这不是纯shell,但你可以把Python脚本封装成命令,在shell里调用。
| 方法 | 精度 | 速度 | 依赖 |
|---|---|---|---|
| awk+sed | 低(仅限简单后缀) | 极快 | 无 |
| grep正则 | 中(需手工匹配) | 快 | 无 |
| Python tldextract | 高(遵循PSL) | 慢(毫秒级) | Python库 |
| 调用在线API | 高 | 取决于网络 | 网络 |
如果你的脚本运行在国内服务器上,没有外网权限,又想精确提取,建议提前下载PSL快照到本地,然后用Python定期更新,具体命令参考:
pip install tldextract
python -c 'import tldextract; print("安装成功")'
之后在shell里写一个函数:
get_main_domain() {
python -c "import tldextract,sys; e=tldextract.extract(sys.argv[1]); print(e.registered_domain)" "$1"
}
调用get_main_domain "mockup.test.example.co.uk",输出example.co.uk,这种方法处理任何后缀都不会错。
推荐使用公共后缀列表(PSL)精确匹配
PSL是Mozilla维护的开源项目,里面不仅包含通用顶级域,还有私有域,在shell里直接解析PSL文本并匹配,是一个比较硬核的玩法。
在shell中调用PSL库的思路
你不需要自己从零写解析器,很多语言都有现成封装,比如Python的tldextract、Node的tldts、Go的golang.org/x/net/publicsuffix,在shell环境里,最省事的方案是调Python。
但如果你的生产环境禁止装任何第三方库,行业专家指出,可以手动维护一份精简后缀表,做法如下:
- 从PSL仓库下载
public_suffix_list.dat。 - 对所有域名,按列表中最长匹配原则,找出匹配的后缀。
- 然后将主域名定义为“后缀左侧第一个标签 + 后缀本身”。
用awk实现最长匹配非常繁琐,通常需要写成循环,这里给出一个Python一行脚本,它不依赖外部库,只用标准库读取本地文件:
python - <<'EOF'
import re
def get_main_domain(domain, suffix_file):
with open(suffix_file) as f:
suffixes = [line.strip() for line in f if line.strip() and not line.startswith('//')]
domain = domain.lower().rstrip('.')
parts = domain.split('.')
for i in range(len(parts)):
for suf in suffixes:
if '.'.join(parts[i:]) == suf or suf.startswith('.'):
reg_len = len(parts) - i
if reg_len >= 2:
return '.'.join(parts[-reg_len-1:])
return domain
EOF
这段逻辑仅供参考,直接跑起来还需要补全分支,如果你不想折腾,还是直接用现成库。
国内服务器环境下的落地实践
很多国内IDC提供的Linux镜像里,默认没有Python的包管理工具,或者内网源不稳定,此时你可以先把tldextract打成wheel包,上传到服务器,用pip install --no-index --find-links=/path/to/dir tldextract离线安装,这个过程不算复杂,但要注意Python版本兼容性。
如果连pip都省了,纯shell方案就要靠“提前枚举后缀”,比如简米云、酷番云的活动域名后缀常见为.cn、.com.cn、.net.cn,你可以写一个case语句:
case "$domain" in
.com.cn|.net.cn|.org.cn)
echo "$domain" | sed -E 's/^[^.]+.([^.]+.[^.]+.[^.]+)$/1/'
;;
)
echo "$domain" | awk -F. '{print $(NF-1)"."$NF}'
;;
esac
这样在特定场景下误差很小,但“特定场景”意味着你需要提前知道所有可能的复合后缀,一旦遇到.cloud、.shop等新通用顶级域,又会出错。
实际场景:从日志、URL、证书里提取主域名
处理Apache或Nginx日志时,域名往往还带着端口或路径,比如https://user:pass@www.example.com:8080/path?query=1,直接提取前必须清理。
提取前先清理协议和路径
一个健壮的shell提取流程分三步:
- 去掉协议头:
sed -E 's#(^w+://|^w+@)##' - 去掉路径和参数:
cut -d'/' -f1,再cut -d'?' -f1 - 去掉端口端口:
cut -d':' -f1
组合起来可以写成:
echo "https://api.example.co.uk:8443/v1/user?name=tom" | sed -E 's#(^w+://)##' | cut -d'/' -f1 | cut -d':' -f1
输出api.example.co.uk,这时候再丢给上面的get_main_domain函数就行。
纯shell提取与调用外部命令的性能差异
在百万行日志上跑提取操作,纯sed和awk是毫秒级批量处理,而每个域名都开一次python -c会慢几十倍,性能敏感的场景,建议一次性把域名列表读入Python循环:
cat domains.txt | python -c '
import sys, tldextract
for line in sys.stdin:
line=line.strip()
if line:
e=tldextract.extract(line)
print(e.registered_domain)
'
注意批量调用与单次调用的区别:单次调用是频繁启动Python解释器,开销很大;批量读入只启动一次,速度可接受,这个经验适合日志分析、GEO爬虫、广告平台做域名归因等场景。
shell提取顶级主域名,没有银弹,简单数据用awk和sed足够,复杂后缀必须上PSL或成熟库。核心结论:先明确你的域名后缀范围,再决定用“切几段”还是“查表”。 纯shell适合已知后缀的批量任务,Python调库适合全场景覆盖。
Q&A:shell提取域名主域名的常见疑问
如何用shell提取域名主域名而不引入额外依赖?
如果你的环境不允许装Python库,使用awk加case匹配已知复合后缀,首选思路是清洗域名后,用awk -F. '{if (NF<=2) print; else print $(NF-1)"."$NF}',但遇到com.cn会错,因此需要先判断后缀是否在复合后缀列表中,这可以通过grep关键词实现,比如echo "$domain" | grep -E '.(cn|uk|jp)$'再单独处理,纯shell方案永远无法覆盖所有后缀,但针对特定业务足够。
带`www`的域名和顶级主域名有什么区别?
www.example.com是常见子域名,example.com才是顶级主域名,在shell中用sed 's/^www.//'去除www前缀即可得到主域名,前提是域名仅有一层子域,如果域名是www.sub.example.com,直接去www后你会得到sub.example.com,这仍然不是主域名,所以必须先搞清楚层级,再决定保留几段。
国内服务器能否免费实现准确提取?
可以,Python的tldextract库是开源免费的,离线下载后放到服务器上,只要Python环境能跑,就不需要外网,如果你不想用库,从Mozilla官网手动下载public_suffix_list.dat,然后写一个简单的分层匹配脚本,同样免费,成本只是服务器上的一次配置时间。
首发原创文章,作者:王坚,如若转载,请注明出处:https://idctop.com/article/619567.html





