如何用Awk高效匹配提取用户信息(不使用while循环)
问题场景
在Linux环境下,需要从LDIF备份文件backup.ldif中批量提取listtodelete.txt里指定用户的完整信息块(从dn:行到空行前的所有内容)。原脚本用while循环逐行调用Awk,因反复扫描大文件导致速度过慢,需改用单Awk命令完成。
现有文件内容
- backup.ldif(LDIF格式备份):
dn: uid=testuser1,ou=people,ou=identities
objectClass: inetOrgPerson
objectClass: organizationalPerson
objectClass: persondn: uid=testuser1,ou=people,ou=identities
objectClass: inetOrgPerson
objectClass: organizationalPerson
objectClass: person
- listtodelete.txt(目标用户dn列表):
dn: uid=testuser1,ou=people,ou=identities
低效的原脚本
while read line do delcommand=" awk '/"$line"/,/pattern|^$/' backup.ldif >> backupfiledeleted.txt eval "$delcommand" done < listtodelete.txt
高效Awk解决方案
直接用Awk一次性处理两个文件,仅扫描backup.ldif一次,大幅提升效率:
单行命令
awk 'NR==FNR { targets[$0]; next } /^dn:/ { in_target = ($0 in targets) } in_target { print; if ($0 == "") in_target = 0 }' listtodelete.txt backup.ldif > backupfiledeleted.txt
拆分脚本(可读性更强)
创建extract_users.awk文件:
# 处理第一个文件(listtodelete.txt),存储所有目标dn NR==FNR { targets[$0] next } # 遇到dn行时,判断是否在目标列表中,设置输出标记 /^dn:/ { in_target = ($0 in targets) } # 如果标记为真,打印当前行;遇到空行时关闭标记 in_target { print if ($0 == "") { in_target = 0 } }
执行命令:
awk -f extract_users.awk listtodelete.txt backup.ldif > backupfiledeleted.txt
脚本逻辑说明
NR==FNR:Awk内置变量NR是当前处理的总行数,FNR是当前文件的行数。当两者相等时,说明正在处理第一个输入文件(listtodelete.txt),把每行的dn存入关联数组targets。/^dn:/:匹配到用户信息块的起始行(dn:开头),检查当前dn是否在targets数组中,决定是否开启输出标记in_target。in_target:如果标记为真,打印当前行;当遇到空行时,说明当前用户信息块结束,把标记设为假,停止输出。
最终输出
执行后backupfiledeleted.txt的内容:
dn: uid=testuser1,ou=people,ou=identities
objectClass: inetOrgPerson
objectClass: organizationalPerson
objectClass: persondn: uid=testuser1,ou=people,ou=identities
objectClass: inetOrgPerson
objectClass: organizationalPerson
objectClass: person
内容的提问来源于stack exchange,提问作者Cj Calaguian

