awk查找记录中的所有匹配项,但限制在这些行上的某些字段

时间:2014-05-19 21:03:31

标签: awk

我的记录如下:

interface Vlan5
 description customerA
 ip address 1.1.1.1 255.255.255.0
 ip address 2.2.2.1 255.255.255.0
 ip address 3.3.3.1 255.255.255.0
 no ip redirects
 no ip unreachables
 no ip proxy-arp
 standby delay reload 90
 standby 9 ip 1.1.1.1
 standby 9 ip 2.2.2.1 secondary
 standby 9 ip 3.3.3.1 secondary
 standby 9 timers 2 6
 standby 9 preempt delay minimum 60

我需要找到“ip address”的所有匹配项,并从这些行(IP地址)中获取第3和第4个字段。我已经得到了它,所以我正在查看正确的记录,但无法弄清楚如何在给定记录中的字段上返回多个匹配,其位置将如此变化。这是非工作代码片段,它让我返回“ip地址”,但我不知道如何获得后面的两个字段(或者如果这是最好的方法)。

if ... blah blah

custvlan=$(echo $i | awk 'BEGIN { FS="," } { print $4 }')

awk -v custvlan=$custvlan 'BEGIN { RS="!"; FS=" " }
{ if ( $1 ~ "interface" && $2 ~ "Vlan" )
    { seenvlan=gensub(/^Vlan/, "", "g", $2)
        if ( seenvlan == custvlan )
            match($0,/ip address/); print substr($0,RSTART,RLENGTH)
    }
}
END {
}' device-config-file

我也尝试将RS重置为新行,希望它能以嵌套的方式工作,但它不会出现。以下修改的示例打印上面第一个示例中的字段3和4,而不是1.1.1.1 255.255.255.0

if ( seenvlan == custvlan )
    RS="\n"; print "this is seenvlan " seenvlan
    if ( $1 ~ ip && $2 ~ address )
        print $3 " " $4

3 个答案:

答案 0 :(得分:0)

您可以使用split()为整个块添加换行符,并为每行split()再次提取字段并检查前两个字段,例如:

awk -v custvlan=$custvlan 'BEGIN { RS="!"; FS=" " }
{ if ( $1 ~ "interface" && $2 ~ "Vlan" )
    { seenvlan=gensub(/^Vlan/, "", "g", $2)
        if ( seenvlan == custvlan )
            split($0, lines, "\n")
            for (l in lines) {
                line = lines[l]
                split(line, fields, " ")
                if (fields[1] == "ip" && fields[2] == "address") {
                    print fields[3], fields[4]
                }
            }  
    }
}
END {
}' device-config-file

它产生:

1.1.1.1 255.255.255.0
2.2.2.1 255.255.255.0
3.3.3.1 255.255.255.0

答案 1 :(得分:0)

您可以在不使用RS的情况下执行此操作。例如,当bash中custvlan设置为5时:

awk -v custvlan=$custvlan '/^interface/ { show=$2=="Vlan" custvlan ? 1 : 0 }
    show && /ip address/ { print $3,$4 }' device-config-file
1.1.1.1 255.255.255.0
2.2.2.1 255.255.255.0
3.3.3.1 255.255.255.0

创建虚拟"记录"设置show变量与custvlan变量匹配,仅在ip address设置时打印出show行的数据。

答案 2 :(得分:0)

另一个解决方案,使用RS="!"来识别块(如上面给出的另一个答案,我假设是Cisco IOS配置格式),并FS="\n"将每个块拆分成行。测试interface VlanX(命令行中预期的custvlan),然后依次循环遍历块中的每一行,并在空格上分割以ip address开头的那些行。针对空字段调整的字段编号和数组索引。为了提高效率,它只假设一个这样的块,所以一旦发现它就会退出。

在Mac OS X 10.9上使用/usr/bin/awkgawkmawk进行了测试。

    BEGIN {
        RS = "!"
        FS = "\n"
    }

    $2 ~ "^ *interface Vlan" custvlan {
        for (i=2; i<=NF; ++i) {
            if ($i ~ /^ *ip address /) {
                split($i, a, / */)
                print a[4], a[5]
            }
        }
        exit 0
    }

示例输入:

    !
    ! Last configuration change at 16:21:26 EEST Thu Sep 6 2012 by admin
    ! NVRAM config last updated at 16:21:46 EEST Thu Sep 6 2012 by admin
    !
    version 15.1
    service timestamps debug datetime localtime
    service timestamps log datetime localtime
    no platform punt-keepalive disable-kernel-core
    !
    !
    interface Vlan5
     description customerA
     ip address 1.1.1.1 255.255.255.0
     ip address 2.2.2.1 255.255.255.0
     ip address 3.3.3.1 255.255.255.0
     no ip redirects
     no ip unreachables
     no ip proxy-arp
     standby delay reload 90
     standby 9 ip 1.1.1.1
     standby 9 ip 2.2.2.1 secondary
     standby 9 ip 3.3.3.1 secondary
     standby 9 timers 2 6
     standby 9 preempt delay minimum 60
    !
    interface Vlan6
     description customerB
     ip address 4.4.4.4 255.255.255.0
     ip address 5.5.5.1 255.255.255.0
     ip address 6.6.6.1 255.255.255.0
     no ip redirects
     no ip unreachables
     no ip proxy-arp
     standby delay reload 90
     standby 9 ip 1.1.1.1
     standby 9 ip 2.2.2.1 secondary
     standby 9 ip 3.3.3.1 secondary
     standby 9 timers 2 6
     standby 9 preempt delay minimum 60
    !
    end

用法:

    script.awk custvlan=5 sample.txt
    => 1.1.1.1 255.255.255.0
    => 2.2.2.1 255.255.255.0
    => 3.3.3.1 255.255.255.0

    script.awk custvlan=6 sample.txt
    => 4.4.4.4 255.255.255.0
    => 5.5.5.1 255.255.255.0
    => 6.6.6.1 255.255.255.0

以下是一个更强大的解决方案(例如,安全地防止流浪!个字符),需要mawkgawk,它们支持RS BEGIN { RS = "\n( *!\n)+" FS = "\n" } $1 ~ "^ *interface Vlan" custvlan { for (i = 2; i <= NF; ++i) { if ($i ~ /^ *ip address /) { split($i, a, / */) print a[4], a[5] } } exit 0 } 中的正则表达式{1}}。用法是一样的:

{{1}}