使用SED匹配IPv4后删除尾部冒号及端口 保留完整IPv6地址
问题背景
现有脚本需要匹配openvpn状态日志中指定私网IP对应的行,打印第三列内容。第三列存在两种取值:
- IPv4地址:末尾固定附带
:PORT格式的数字端口后缀 - IPv6地址:无额外后缀,地址本身包含多个冒号分隔符
现有处理方案存在两类典型错误:
- 直接执行
sed 's/:.*//g'删除冒号后所有内容,会破坏IPv6地址的原有格式 - 为awk指定多分隔符
[,:],虽能正确提取IPv4地址,但会按冒号截断IPv6地址,仅输出第一个地址段
核心需求:仅剥离IPv4地址末尾的:PORT后缀,完整保留IPv6地址
测试样例
测试用openvpn-status.log文件内容如下:
$ cat openvpn-status.log 10.13.0.27,ijegunbead-4,74.201.72.222:49911,2022-06-26 02:55:26 10.13.0.23,biddy-h-1,2803:4600:1111:17ec:a821:1a8:53ca:760d,2022-06-26 02:55:28
原有提取命令:
dst1=$(egrep -w ^$dst /etc/openvpn/openvpn-status.log | awk -F'[,:]' '{print $3}')
命令错误输出:
74.201.72.222 2803
期望正确输出:
74.201.72.222 2803:4600:1111:17ec:a821:1a8:53ca:760d
之前尝试的失败命令存在两个问题:一是管道位置错误,sed未接收到子shell输出的内容;二是sed正则替换逻辑写反,会误删IPv4地址本身。
# 错误示例,请勿使用 dst1=$(egrep -w ^$dst /etc/openvpn/openvpn-status.log | awk -F',' '{print $3}') | sed 's/[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+:*//g'
正确实现方案
直接用awk单命令完成匹配、判断、替换全流程,避免多管道开销,逻辑更精准:
dst1=$(awk -F',' -v match_ip="$dst" ' $1 == match_ip { # 仅当第三列是带端口的IPv4地址时,删除末尾的端口后缀 if ($3 ~ /^([0-9]{1,3}\.){3}[0-9]{1,3}:[0-9]+$/) { sub(/:[0-9]+$/, "", $3) } print $3 exit }' /etc/openvpn/openvpn-status.log)
逻辑说明
- 仅用逗号作为字段分隔符,从根源避免IPv6地址被冒号截断
- 通过
-v参数传入shell变量,避免引号转义问题,匹配第一列完全等于目标IP的行,比grep模糊匹配更准确,不会出现前缀误判 - 对第三列做格式校验:只有符合「IPv4+冒号+数字端口」格式的内容,才会删除末尾的
:端口后缀;IPv6地址会原样保留 - 匹配到目标行后直接
exit退出,适合大日志文件场景,减少无效遍历
执行后即可得到预期输出,完全满足需求。
内容的提问来源于stack exchange,提问作者Giancarlo D
相关产品推荐
相关产品推荐

