如何完善Bash双层循环脚本以提取Cisco ASA主机对象中带NAT与无NAT的主机信息
解决Cisco ASA主机对象提取(含/不含NAT地址)的问题
你的需求很清晰——从ASA的对象配置文件里筛选出主机类型的条目,不管有没有NAT映射都要输出。原脚本的问题在于嵌套循环效率极低,而且只处理了能匹配到NAT条目的主机,完全漏掉了没有NAT配置的那些。下面给你两种解决方案,优先推荐用awk,它处理这类文本关联任务比bash循环高效得多。
方案一:用Awk实现高效处理(推荐)
Awk天生擅长处理需要关联不同行数据的场景,我们可以先把所有主机的基础信息和NAT映射分别存入数组,最后统一输出结果:
BEGIN { FS = " " # 设置字段分隔符为空格 } # 处理主机类型的对象行,存储主机名和内部IP /object network.*host/ { hostname = $3 internal_ip = $5 hosts[hostname] = internal_ip } # 处理静态NAT行,存储主机名和NAT地址 /object network.*static/ { hostname = $3 nat_ip = $6 nat_map[hostname] = nat_ip } # 所有行处理完后,按要求输出结果 END { for (host in hosts) { if (nat_map[host] != "") { printf "%s,%s,%s\n", host, hosts[host], nat_map[host] } else { printf "%s,%s\n", host, hosts[host] } } }
把上面的代码保存为parse-hosts.awk,然后运行:
awk -f parse-hosts.awk vs-hosts-objects.txt
输出结果(完全匹配你的要求):
SRV002,172.16.0.2 SRV003,172.16.0.3,87.88.89.90 SRV012,172.16.0.12,87.88.89.91 SRV013,172.16.0.13
方案二:改进你的Bash脚本
如果你更倾向于用bash实现,我们可以先把所有主机信息和NAT信息分别存入关联数组,再遍历输出,避免原脚本的嵌套循环(原脚本会读取文件N²次,效率极低):
#!/bin/bash declare -A host_ips declare -A nat_ips # 第一步:收集所有主机的内部IP while read -r line; do if [[ $line == *"host"* ]]; then hostname=$(echo "$line" | awk '{print $3}') ip=$(echo "$line" | awk '{print $5}') host_ips["$hostname"]="$ip" fi done < vs-hosts-objects.txt # 第二步:收集所有主机的NAT地址 while read -r line; do if [[ $line == *"static"* ]]; then hostname=$(echo "$line" | awk '{print $3}') nat_ip=$(echo "$line" | awk '{print $6}') nat_ips["$hostname"]="$nat_ip" fi done < vs-hosts-objects.txt # 第三步:遍历输出所有主机信息 for hostname in "${!host_ips[@]}"; do ip=${host_ips[$hostname]} nat_ip=${nat_ips[$hostname]:-""} if [[ -n $nat_ip ]]; then echo "$hostname,$ip,$nat_ip" else echo "$hostname,$ip" fi done
这个脚本只读取文件两次,效率比原脚本高很多,而且能正确输出所有主机条目,不管有没有NAT配置。
原脚本失败的原因
原脚本的嵌套循环会每读取一条主机行就遍历整个文件找对应的NAT条目,而且只输出能匹配到NAT的主机,完全没有处理那些没有对应NAT条目的主机,所以漏掉了SRV002、SRV013这类条目。上面的两种方案都是先收集全量数据,再统一输出,从根本上解决了这个问题。
内容的提问来源于stack exchange,提问作者Ian S.
相关产品推荐
相关产品推荐

