Shell脚本中匹配特定字符间内容的正则失效问题排查
Kubectl镜像列表处理:sed/awk正则无效的原因及解决办法
问题背景
我需要清理Kubectl导出的Pod镜像列表内容,删除不必要字符。首先通过以下命令获取Pod镜像列表并保存到temp文件:
kubectl get pods -n $1 -o jsonpath='{range .items[*]}{@.spec.containers[*].image}{","}{@.status.containerStatuses[*].imageID}{"\n"}{end}'
尝试用sed删除逗号(,)到@之间的所有字符(含@),在Regex101中验证有效的正则,在shell中执行却无效果:
sed -i 's/(?<=\,)(.*?)(?<=\@)//g' temp
改用awk命令也未得到预期结果:
awk '!/(?<=\,)(.*?)(?<=\@)/' temp
示例输入
docker.elastic.co/elasticsearch/elasticsearch:7.17.5,docker-pullable://docker.elastic.co/elasticsearch/elasticsearch@sha256:76344d5f89b13147743db0487eb76b03a7f9f0cd55abe8ab887069711f2ee27d docker.io/bitnami/kafka:3.3.1-debian-11-r11,docker-pullable://bitnami/kafka@sha256:be29db0e37b6ab13df5fc14988a4aa64ee772c7f28b4b57898015cf7435ff662 docker.io/bitnami/mongodb:6.0.3-debian-11-r0,docker-pullable://bitnami/mongodb@sha256:e7438d7964481c0bcfcc8f31bca2d73022c0b7ba883143091a71ae01be6d9edb docker.io/bitnami/postgresql:14.1.0-debian-10-r80,docker-pullable://bitnami/postgresql@sha256:6eb9c4ab3444e395df159e2cad21f283e4bf30802958467590c886f376dc9959 docker.io/bitnami/zookeeper:3.8.0-debian-11-r47,docker-pullable://bitnami/zookeeper@sha256:0f3169499c5ee02386c3cb262b2a0d3728998d9f0a94130a8161e389f61d1462
预期输出
docker.elastic.co/elasticsearch/elasticsearch:7.17.5,sha256:76344d5f89b13147743db0487eb76b03a7f9f0cd55abe8ab887069711f2ee27d docker.io/bitnami/kafka:3.3.1-debian-11-r11,sha256:be29db0e37b6ab13df5fc14988a4aa64ee772c7f28b4b57898015cf7435ff662 docker.io/bitnami/mongodb:6.0.3-debian-11-r0,sha256:e7438d7964481c0bcfcc8f31bca2d73022c0b7ba883143091a71ae01be6d9edb docker.io/bitnami/postgresql:14.1.0-debian-10-r80,sha256:6eb9c4ab3444e395df159e2cad21f283e4bf30802958467590c886f376dc9959 docker.io/bitnami/zookeeper:3.8.0-debian-11-r47,sha256:0f3169499c5ee02386c3cb262b2a0d3728998d9f0a94130a8161e389f61d1462
请问是哪里出错了,还是Unix/shell中的正则规则不同?
原因分析
- sed正则语法不兼容:sed默认使用基本正则表达式(BRE),即使添加
-r参数启用扩展正则表达式(ERE),也不支持PCRE(Perl兼容正则表达式)中的正向预查(?<=...)这类零宽断言语法。你在Regex101中用的是PCRE规则,但shell里的sed不支持,导致匹配失败,没有替换效果。 - sed正则逻辑错误:你的正则试图通过预查定位要删除的内容,但sed的替换是需要直接匹配到目标内容才能替换,这种预查的写法不符合sed的工作逻辑。
- awk命令逻辑错误:
awk '!/.../'是用来过滤不匹配正则的行,而不是替换行内的内容。同时awk默认也不支持PCRE的正向预查语法,所以这条命令完全达不到修改内容的目的。
解决办法
方法1:使用sed简化正则
直接匹配逗号到@之间的所有内容,替换为单个逗号,语法简单且兼容所有sed版本:
sed -i 's/,.*@/,/' temp
解释:,.*@匹配从逗号开始到最后一个@的所有字符(sed默认是贪婪匹配,正好覆盖你要删除的部分),替换为,后,就保留了逗号前的镜像名和@后的sha256值。
方法2:使用awk处理
通过分割字符串实现,逻辑清晰:
awk -F '@' '{split($1, arr, ","); print arr[1] "," $2}' temp
解释:
- 用
@作为分隔符,将每行分成两部分,$2就是sha256开头的部分 - 再将第一部分$1用逗号分割,arr[1]就是镜像名
- 最后拼接镜像名+逗号+$2得到预期结果
内容的提问来源于stack exchange,提问作者airen
相关产品推荐
相关产品推荐

