如何使用AWK在指定列精确匹配完整字符串 避免子串误匹配
awk精确匹配逗号分隔列表内指定字符串的实现方法
问题背景
使用awk做字符串匹配时遇到子串误匹配问题,待处理文件为sup_groups.txt,文件每行格式为group_name:pw:group_id:user1,user2...,具体内容:
adm:x:4:syslog,adm1 admins:x:1006:adm2,adm12,manuel ssl-cert:x:122:postgres ala2:x:1009:aceto,salvemini conda:x:1011:giovannelli,galise,aceto,caputo,haymele,salvemini,scala,adm2,adm12 adm1Group:x:1022:adm2,adm1,adm3 docker:x:998:manuel
需求是提取第四列用户列表中精确包含用户adm1的行,输出第一列的组名。最初使用的命令是简单子串匹配:
awk -F: '$4 ~ "adm1" {print $1}' sup_groups.txt
由于文件中存在adm12这类名称包含adm1的用户,命令输出了错误结果:
adm admins conda adm1Group
其中admins、conda两行是因为包含adm12被误匹配,预期正确结果只有adm和adm1Group两行。
问题解决
自写方案的问题
你自己补充的正则写法$4 ~ "adm,|adm1$|:adm1,"有两个明显漏洞:
- 第一个匹配规则
adm,会匹配所有以adm开头的用户项,比如adm2,、adm12,都会命中,完全无法过滤误匹配 - 规则遗漏了
adm1出现在用户列表首位的场景,同时:adm1,的写法完全无效——因为按冒号分割后,第四列的内容里不会再包含冒号
正确实现方式
两个经过验证的可用写法,都能得到正确结果:
- 正则边界匹配(写法最简洁)
利用awk正则的单词边界符\<和\>,仅匹配独立的adm1单词,不会匹配前后拼接其他字符的adm12:awk -F: '$4 ~ /\<adm1\>/ {print $1}' sup_groups.txt - 字段拆分比对(逻辑最严谨,无正则歧义)
把第四列按逗号拆分成独立的用户名,逐个做精确相等判断,只要存在匹配项就输出组名,完全避免正则规则带来的误判:awk -F: '{ split($4, users, ",") for(idx in users) { if(users[idx] == "adm1") { print $1 break } } }' sup_groups.txt
两个命令执行后的输出均为预期结果:
adm adm1Group
内容的提问来源于stack exchange,提问作者sirducas
相关产品推荐
相关产品推荐

