在日常的系统管理、日志分析或网络自动化任务中,我们经常需要从一串完整的域名(Fully Qualified Domain Name, FQDN)中提取出其“主域名”,从
www.example.com
中提取
example.com
,或从
blog.news.co.uk
中提取
news.co.uk
,这个过程看似简单,但由于顶级域名(TLD)的复杂性,一个鲁棒的解决方案需要考虑多种情况,本文将详细介绍在Shell环境下提取主域名的几种方法,从简单的字符串处理到使用专业工具,并分析各自的优劣。
什么是主域名?
在深入探讨之前,我们先明确“主域名”的定义,主域名通常指的是可注册的域名部分,它由一个域名标签和一个公共后缀组成,公共后缀不仅仅包括、、等传统顶级域名,还包括像、、这样的国家代码顶级域名下的二级域名,以及新通用顶级域名如
.github.io
,简单地用点号分割域名并取最后两部分在很多情况下是错误的。
使用基础文本处理工具(适用于简单场景)
对于结构非常固定的域名,例如只处理、、等顶级域名,我们可以使用、等基础工具。
使用命令
命令可以按指定分隔符切割字符串,我们可以用点号作为分隔符。
# 假设我们处理的是 www.example.comdomain="www.example.com"echo $domain | cut -d '.' -f 2,3# 输出: example.com
这个命令的逻辑是:以为分隔符,提取第2和第3个字段。
局限性:
这种方法非常脆弱,如果域名是
sub.domain.co.uk
,它将错误地输出,而不是我们期望的
domain.co.uk
。
使用命令
提供了更强大的字段处理能力,但对于这个问题,其核心思路与类似。
domain="www.example.com"echo $domain | awk -F '.' '{print $(NF-1)"."$NF}'# 输出: example.com
这里,设置字段分隔符为点号,是的内置变量,代表字段总数。和分别代表倒数第二个和最后一个字段。
局限性: 与一样,这种方法无法正确处理多级公共后缀。
使用专业工具
tldextract
(推荐的最佳实践)
为了准确、鲁棒地提取主域名,最佳方案是使用能够识别公共后缀列表(Public Suffix List, PSL)的工具。
tldextract
就是这样一款优秀的工具,它是一个Python库,同时也提供了命令行接口。
PSL是由Mozilla维护的一个公共后缀列表,它包含了所有已知的公共后缀,是处理此类问题的黄金标准。
安装
tldextract
你需要确保系统已安装Python和pip,然后通过pip安装:
pip install tldextract
使用
tldextract
tldextract
的使用非常直观,它会将一个完整的域名分解为三个部分:子域名、主域名和后缀。
# 示例1:简单域名tldextract "www.example.com"# 输出:# example.com# www# 示例2:复杂公共后缀tldextract "blog.news.co.uk"# 输出:# news.co.uk# blog# 示例3:特殊后缀tldextract "user.github.io"# 输出:# github.io# user
tldextract
默认会输出三行,分别是主域名+后缀、子域名,为了得到我们想要的“主域名”(即主域名+后缀),我们可以这样组合命令:
domain="blog.news.co.uk"tldextract $domain | head -n 1# 输出: news.co.uk
或者,如果需要更精确的控制,可以获取其JSON格式的输出:
tldextract --json "blog.news.co.uk" | jq -r '.domain + "." .suffix'# 输出: news.co.uk
(这里假设安装了来解析JSON)
使用纯Bash实现(无外部依赖)
在某些受限环境中,可能无法安装任何外部工具,我们可以尝试用纯Bash实现,但必须承认,一个完美的纯Bash实现几乎是不可能的,因为它无法动态获取PSL,以下是一个基于假设的函数,它假设后缀只有一级或两级。
function get_main_domain() {local domain="$1"# 移除端口号(如果存在)domain=$(echo $domain | cut -d ':' -f 1)# 按点号分割成数组IFS='.' read -ra parts <<< "$domain"local len=${#parts[@]}if [ $len -le 2 ]; thenecho "$domain"elif [ $len -eq 3 ]; then# 简单判断,如果最后一个部分是两个字母(国家代码),则取后三部分if [[ ${parts[-1]} =~ ^[a-z]{2}$ ]]; thenecho "${parts[-3]}.${parts[-2]}.${parts[-1]}"elseecho "${parts[-2]}.${parts[-1]}"fielse# 对于更长的域名,这个逻辑就不准确了echo "${parts[-2]}.${parts[-1]}"fi}get_main_domain "www.example.com"# 输出: example.comget_main_domain "www.domain.co.uk"# 输出: domain.co.ukget_main_domain "sub.www.domain.com"# 输出: domain.com (不准确,应为www.domain.com)
警告:
此方法仅作为演示,其逻辑非常简陋,不适用于生产环境,它无法处理
.github.io
或等复杂情况。
方法对比
下表小编总结了上述几种方法的优缺点:
| 方法 | 易用性 | 准确性 | 依赖性 | 适用场景 |
|---|---|---|---|---|
| 高 | 低 | 无(Shell内置) | 处理格式固定的简单域名,如内部系统日志 | |
tldextract
|
高 | 极高 | Python, pip | 任何需要准确提取主域名的生产环境、自动化脚本 |
| 纯Bash函数 | 中 | 低 | 无(Shell内置) | 无法安装外部工具的极端受限环境,且需容忍其不准确性 |
虽然使用基础的Shell工具可以解决部分简单问题,但为了确保在各种复杂域名下的准确性和可靠性,强烈推荐使用
tldextract
,它通过维护和引用公共后缀列表,为我们提供了一个标准、权威且易于使用的解决方案,是处理域名提取任务的最佳选择。
相关问答FAQs
Q1: 如果我的服务器环境是隔离的,无法连接互联网安装
tldextract
,我该怎么办?
A1: 在完全隔离的环境中,你无法使用安装,一个可行的替代方案是手动下载
tldextract
及其依赖(特别是PSL数据文件),然后将其打包到你的应用镜像或部署包中。
tldextract
允许你通过环境变量
TLDEXTRACT_CACHE_FILE
指定一个本地的PSL缓存文件路径,你可以先在有网络的环境中运行一次
tldextract
,它会下载并缓存PSL文件(通常在
~/.cache/tldextract/
目录下),然后将这个缓存目录连同你的脚本一起复制到隔离环境中,这样,
tldextract
就能使用本地的缓存文件正常工作,而无需联网。
Q2:
tldextract
和直接用正则表达式(如)处理有什么本质区别?
A2: 本质区别在于“知识库”,正则表达式是基于模式匹配的,它本身“不知道”哪些字符串是公共后缀,你可以写一个非常复杂的正则表达式来匹配已知的公共后缀,但这个列表是不断变化的,你需要手动维护它,这既繁琐又容易出错,而
tldextract
的核心优势在于它依赖一个由社区维护的、权威的公共后缀列表(PSL),它不是在“猜测”后缀是什么,而是在“查询”一个已知的数据库。
tldextract
的准确性和可维护性远超任何基于静态正则表达式的解决方案,能够正确处理新旧、各种类型的公共后缀。
在linux 系统中使用adduser 命令新建的用户无法使用
没有添加家目录吧,这样默认会切到 root,而根目录不可访问。可以修改用户信息: usermod -d /home/username username
shell 中cut到的字符怎么使用
shell_cut实例cut是一个选取命令,就是将一段数据经过分析,取出我们想要的。 一般来说,选取信息通常是针对行来进行分析的,并不是整篇信息分析的。 (1)其语法格式为:cut [-bn] [file] 或 cut [-c] [file] 或 cut [-df] [file]使用说明cut 命令从文件的每一行剪切字节、字符和字段并将这些字节、字符和字段写至标准输出。 如果不指定 File 参数,cut 命令将读取标准输入。 必须指定 -b、-c 或 -f 标志之一。 主要参数-b :以字节为单位进行分割。 这些字节位置将忽略多字节字符边界,除非也指定了 -n 标志。 -c :以字符为单位进行分割。 -d :自定义分隔符,默认为制表符。 -f :与-d一起使用,指定显示哪个区域。 -n :取消分割多字节字符。 仅和 -b 标志一起使用。 如果字符的最后一个字节落在由 -b 标志的 List 参数指示的范围之内,该字符将被写出;否则,该字符将被排除。 (2)cut一般以什么为依据呢? 也就是说,我怎么告诉cut我想定位到的剪切内容呢?cut命令主要是接受三个定位方法:第一,字节(bytes),用选项-b第二,字符(characters),用选项-c第三,域(fields),用选项-f(3)以字节定位举个例子吧,当你执行ps命令时,会输出类似如下的内容:[rocrocket@rocrocket programming]$ whorocrocket -01-08 11:07rocrocket pts/-01-08 11:23 (:0.0)rocrocket pts/-01-08 14:15 (:0.0)如果我们想提取每一行的第3个字节,就这样:[rocrocket@rocrocket programming]$ whocut -b 3ccc(4) 如果字节定位中,我想提取第3,第4、第5和第8个字节,怎么办?-b支持形如3-5的写法,而且多个定位之间用逗号隔开就成了。 看看例子吧:[rocrocket@rocrocket programming]$ whocut -b 3-5,8croecroecroe但有一点要注意,cut命令如果使用了-b选项,那么执行此命令时,cut会先把-b后面所有的定位进行从小到大排序,然后再提取。 可不能颠倒定位的顺序哦。 这个例子就可以说明这个问题:[rocrocket@rocrocket programming]$ whocut -b 8,3-5croecroecroe(5) 还有哪些类似3-5这样的小技巧,列举一下吧![rocrocket@rocrocket programming]$ whorocrocket -01-08 11:07rocrocket pts/-01-08 11:23 (:0.0)rocrocket pts/-01-08 14:15 (:0.0)[rocrocket@rocrocket programming]$ whocut -b -3rocrocroc[rocrocket@rocrocket programming]$ whocut -b 3-crocket -01-08 11:07crocket pts/-01-08 11:23 (:0.0)crocket pts/-01-08 14:15 (:0.0)想必你也看到了,-3表示从第一个字节到第三个字节,而3-表示从第三个字节到行尾。 如果你细心,你可以看到这两种情况下,都包括了第三个字节c。 如果我执行whocut -b -3,3-,你觉得会如何呢?答案是输出整行,不会出现连续两个重叠的c的。 看:[rocrocket@rocrocket programming]$ whocut -b -3,3-rocrocket -01-08 11:07rocrocket pts/-01-08 11:23 (:0.0)rocrocket pts/-01-08 14:15 (:0.0)(6)给个以字符为定位标志的最简单的例子吧!下面例子你似曾相识,提取第3,第4,第5和第8个字符:[rocrocket@rocrocket programming]$ whocut -c 3-5,8croecroecroe不过,看着怎么和-b没有什么区别啊?莫非-b和-c作用一样? 其实不然,看似相同,只是因为这个例子举的不好,who输出的都是单字节字符,所以用-b和-c没有区别,如果你提取中文,区别就看出来了,来,看看中文提取的情况:[rocrocket@rocrocket programming]$ cat cut_星期一星期二星期三星期四[rocrocket@rocrocket programming]$ cut -b 3 cut_����[rocrocket@rocrocket programming]$ cut -c 3 cut_一二三四看到了吧,用-c则会以字符为单位,输出正常;而-b只会傻傻的以字节(8位二进制位)来计算,输出就是乱码。 既然提到了这个知识点,就再补充一句,如果你学有余力,就提高一下。 当遇到多字节字符时,可以使用-n选项,-n用于告诉cut不要将多字节字符拆开。 例子如下:[rocrocket@rocrocket programming]$ cat cut_ cut -b 2����[rocrocket@rocrocket programming]$ cat cut_ cut -nb 2[rocrocket@rocrocket programming]$ cat cut_ cut -nb 1,2,3星星星星(7)域是怎么回事呢?解释解释:)为什么会有域的提取呢,因为刚才提到的-b和-c只能在固定格式的文档中提取信息,而对于非固定格式的信息则束手无策。 这时候域就派上用场了。 如果你观察过/etc/passwd文件,你会发现,它并不像who的输出信息那样具有固定格式,而是比较零散的排放。 但是,冒号在这个文件的每一行中都起到了非常重要的作用,冒号用来隔开每一个项。 我们很幸运,cut命令提供了这样的提取方式,具体的说就是设置间隔符,再设置提取第几个域,就OK了!以/etc/passwd的前五行内容为例:[rocrocket@rocrocket programming]$ cat /etc/passwdhead -n 5root:x:0:0:root:/root:/bin/bashbin:x:1:1:bin:/bin:/sbin/nologindaemon:x:2:2:daemon:/sbin:/sbin/nologinadm:x:3:4:adm:/var/adm:/sbin/nologinlp:x:4:7:lp:/var/spool/lpd:/sbin/nologin[rocrocket@rocrocket programming]$ cat /etc/passwdhead -n 5cut -d : -f 1rootbindaemonadmlp看到了吧,用-d来设置间隔符为冒号,然后用-f来设置我要取的是第一个域,再按回车,所有的用户名就都列出来了!呵呵 有成就感吧!当然,在设定-f时,也可以使用例如3-5或者4-类似的格式:[rocrocket@rocrocket programming]$ cat /etc/passwdhead -n 5cut -d : -f 1,3-5root:0:0:rootbin:1:1:bindaemon:2:2:daemonadm:3:4:admlp:4:7:lp[rocrocket@rocrocket programming]$ cat /etc/passwdhead -n 5cut -d : -f 1,3-5,7root:0:0:root:/bin/bashbin:1:1:bin:/sbin/nologindaemon:2:2:daemon:/sbin/nologinadm:3:4:adm:/sbin/nologinlp:4:7:lp:/sbin/nologin[rocrocket@rocrocket programming]$ cat /etc/passwdhead -n 5cut -d : -f -2root:xbin:xdaemon:xadm:xlp:x(8)如果遇到空格和制表符时,怎么分辨呢?我觉得有点乱,怎么办?有时候制表符确实很难辨认,有一个方法可以看出一段空格到底是由若干个空格组成的还是由一个制表符组成的。 [rocrocket@rocrocket programming]$ cat tab_ is tab is several space finish.[rocrocket@rocrocket programming]$ sed -n l tab_ is tab/tfinish.$this is several space finish.$看到了吧,如果是制表符(TAB),那么会显示为/t符号,如果是空格,就会原样显示。 通过此方法即可以判断制表符和空格了。 注意,上面sed -n后面的字符是L的小写字母哦,不要看错。 (9)我应该在cut -d中用什么符号来设定制表符或空格呢?其实cut的-d选项的默认间隔符就是制表符,所以当你就是要使用制表符的时候,完全就可以省略-d选项,而直接用-f来取域就可以了。 如果你设定一个空格为间隔符,那么就这样:[rocrocket@rocrocket programming]$ cat tab_ cut -d -f 1thisthis注意,两个单引号之间可确实要有一个空格哦,不能偷懒。 而且,你只能在-d后面设置一个空格,可不许设置多个空格,因为cut只允许间隔符是一个字符。 [rocrocket@rocrocket programming]$ cat tab_ cut -d -f 1cut: the delimiter must be a single characterTry `cut --help for more information.(10)cut有哪些缺陷和不足?猜出来了吧?对,就是在处理多空格时。 如果文件里面的某些域是由若干个空格来间隔的,那么用cut就有点麻烦了,因为cut只擅长处理以一个字符间隔的文本内容
本地连接dns缓存无法修复怎么办?
修复网络连接时出现DNS缓存无法清除的问题, 1遇到这种情况,我们能采取的最简单手段是刷新DNS,也就是删除 DNS 解析器缓存中的条目。 点击“开始”-“运行”-输入cmd并点击“确定”,在命令提示符窗口中键入:ipconfig /flushdns2如果上面不行的话,在系统服务里把DNS Client和DHCP client两个服务组件启动针对网络剪刀手 网络执法官 网络特工 等ARP欺骗的攻击 ,可以用网卡修复操作中的清除arp缓存,可以用cmd命令中的 arp -d命令有一个好的办法是在按键精灵中写一个脚本如下:VBS Set Oshell = CreateObject()VBS cmd /c arp -d, vbHideVBS Set Oshell = NothingVBS End SubDelay 1000这个就是每隔1秒清除一次arp缓存,可以自己调整延时!!通过IPConfig提供的信息,可以确定存在于TCP/IP属性中的一些配置上的问题。 例如使用“IPConfig /all”就可以获取主机的详细的配置信息,其中包括IP地址、子网掩码和默认网关、DNS服务器等信息。 通过所获知的信息,可以迅速判断出网络的故障所在。 例如子网掩码为0.0.0.0时,则表示局域网中的IP地址可能有重复的现象存在;如果返回的本地 IP地址显示为169.254.*.*,子网掩码为255.255.0.0,则表示该IP地址是由Windows XP的自动专用IP寻址功能分配的。 这意味着TCP/IP未能找到DHCP服务器,或是没有找到用于网络接口的默认网关。 如果返回的本地IP地址显示为 0.0.0.0,则既可能是DHCP初始化失败导致IP地址无法分配,也可能是因为网卡检测到缺少网络连接或TCP/IP检测到IP地址有冲突而导致的。 众所周知每台计算机要想正常上网需要有一个地址,这个地址就是我们常说的IP地址。 在实际工作中身为网络管理员的我们如何有效的管理这些IP地址呢?为每台计算机设置对应的IP地址,子网掩码,网关地址,DNS地址等网络参数的话固然是可以的,但是非常的烦琐,工作量大不说,在实际应用中很可能经常会出现冲突的现象。 我们如何有效的分配这些网络参数呢?DHCP服务可以帮我们大忙,通过将DHCP服务配置在专业的服务器上,然后为网络中所有普通客户机分配IP等信息是件效率非常高的工作。 不过DHCP在为我们网络管理提供便利的同时也带来了一些问题。 例如网络带宽受影响,客户机经常无法获得正确的地址信息,甚至是无法获得任何信息。 其实这些故障我们都可以按照一定的规律去解决的,今天就由笔者为各位IT168的读者全面介绍排查 DHCP故障的方法。 一、概念篇:在介绍排查DHCP故障之前首先为大家阐明几个概念性的东西,只有理论上充实了,才能更好的理解下面介绍的故障排除的思路。 第一:DHCP服务能够提供什么数据?DHCP服务不是万能的,他只能提供网络层相关的参数,例如IP地址,MASK地址,网关地址,WINS与DNS服务器地址等。 对于更低层的地址,诸如mac地址等信息是无法提供的。 MAC地址是烧录在计算机网卡中的。 第二:多台DHCP服务器是否可以同时运行?DHCP服务器是通过广播包向客户机发送网络信息的,因此如果同一个网络中确切的说是同一个广播域中存在多台DHCP服务器的话,就会出现各个服务器提供各自的网络信息,这样就造成网络中广播数据包的冲突。 客户机不知道该接受哪台DHCP服务器发来的信息。 因此微软公司设置默认情况下同一个广播域网络中只能存在一台DHCP服务器,后设置建立或启用的DHCP将无法工作。 第三:租约是什么?在配置DHCP服务器过程中会设置租约的天数,那么什么是租约呢?在DHCP服务器将网络信息分配数据包发给客户机后会收到客户机发回的答复数据包,接着DHCP服务器会将已经分配出去的IP地址与从客户机接收到的该计算机MAC地址建立一个对应关系,并把这个对应关系保存在DHCP服务器的租约池中。 为什么需要这个租约池呢?一方面为下次分配网络参数信息提高了速度。 不过如果该MAC地址对应条目的客户计算机被移到其他地方或者MAC地址发生了改变的话,如果上面建立的对应关系一直保存在DHCP服务器的租约池中就会造成可用的IP地址数量越来越少,很多有效的地址被无效的MAC占用,因此微软引入了租约这个概念。 通过租约我们可以强制每隔一段时间将DHCP服务器的租约池中保存的对应条目全部清空,从而防止了非法MAC地址霸占合法IP的现象,
希望对你有帮助。














发表评论