BASH在循环中搜索多个字符串的数组

时间:2014-07-26 10:50:22

标签: arrays bash parsing cisco

大家好,感谢您的阅读,

我正在尝试编写一个脚本,该脚本将通过Cisco Configs进行解析,并确定特定VLAN中的接口与否,以及它们是否已关闭。我认为解析数组并搜索我正在寻找的项目并为它们设置变量很容易我遇到了一些问题。下面是脚本的基本部分,它将文件读入数组,而echo只是转储数组。我正在寻找的是一种读取数组的方法:

  • 接口名称
  • switchport access vlan
  • 关闭

基本流程是脚本(interfaces.sh)读入任何* .cfg文件并以数组形式读取接口。此时,它会解析搜索这些字段的数组。如果找到,请设置稍后要使用的值。最后,它获取VLAN和isShut的值,并根据它们的值,报告接口是否在vlan 2中而不是关闭或在另一个vlan中关闭。

将接口放入阵列的基本代码

  ##  BEGIN interfaces.sh ##
  #!/bin/bash
  clear
  ls *.cfg | while read config; do
  IFS=$'\r\n' interfaces=(`sed -n '/^interface/,/!/p' $config `)
  tLen=${#interfaces[@]}
  printf "\b Starting $config... \n"    
  for (( i=0; i<${tLen}; i++ ))
   do
    echo "${interfaces[$i]}" 
   done

  printf "\n\n"
  done

我做的一次尝试

 #!/bin/bash
 clear
 ls *.cfg | while read config; do
 IFS=$'\r\n' interfaces=(`sed -n '/^interface/,/!/p' $config `)
 tLen=${#interfaces[@]}
 printf "\b Starting $config... \n"
 isInt=0
 isShut=0
 VLAN=0

 for (( i=0; i<${tLen}; i++ ))
 do
         if [[ $(echo "${interfaces[$i]}" | grep interface | grep net) ]]; then
                 int_name=${interfaces[$i]}
                 isInt=1
         fi

         if [[ $(echo "${interfaces[$i]}" | grep "access vlan" | grep -v "access vlan 2$") ]]; then
            VLAN="vlan1"
         fi

    if [[ $(echo "${interfaces[$i]}" | grep "access vlan 2$") ]]; then
                VLAN="vlan2"
    fi

         if [[ $(echo "${interfaces[$i]}" | grep -v " shutdown$") ]]; then
            isShut="notShutdown"
         fi

         if [[ $(echo "${interfaces[$i]}" | grep " shutdown$") ]]; then
                 isShut="shut"
    fi



    # This put here to test if the variables vlan and isShut is being set.
    # IF you uncomment this line you can see that the values are set then 
    # on the next pass it is changed of some of the values.  I dont know
    # how to fix this.
    #echo " $int_name vlan=$VLAN isShut=$isShut"

    # Below is the results of the value changing
    # interface Ethernet2/3 vlan=vlan1 isShut=notShutdown
    # interface Ethernet2/3 vlan=vlan2 isShut=notShutdown
    # interface Ethernet2/3 vlan=vlan2 isShut=notShutdown
    # interface Ethernet2/3 vlan=vlan2 isShut=shut
    # interface Ethernet2/3 vlan=vlan2 isShut=notShutdown
    # interface Ethernet2/3 vlan=vlan2 isShut=notShutdown
    # interface Ethernet2/3 is in vlan 2 and is not shutdown


         # End of interface section so reset counters
         if [[ "${interfaces[$i]}" == '!' ]]
           then
                 if [[ "$VLAN" == "vlan1" && "$isShut" == "notShutdown" ]]; then
                         echo "$int_name is NOT in vlan 2 and is not shutdown"
            fi

                 if [[ "$VLAN" == "vlan1" && "$isShut" == "shut" ]]; then
                         echo "$int_name is NOT in vlan 2 and is shutdown"
            fi

                 if [[ "$VLAN" == "vlan2" && "$isShut" == "notShutdown" ]]; then
                         echo "$int_name is in vlan 2 and is not shutdown"
            fi

                 if [[ "$VLAN" == "vlan2" && "$isShut" == "shut" ]]; then
                         echo "$int_name is in vlan 2 and is shutdown"
            fi

    isInt=0
    isShut=0
    vlan=0

         fi
 done

 printf "\n\n"
 done

开始Cisco Config#

  # Save this section as config.txt
Current configuration : 2271 bytes
 !
 ! Last configuration change at 18:30:45 CET Fri Jul 25 2014
 !
 version 15.0
 no service pad
 service timestamps debug datetime msec
 service timestamps log datetime msec
 no service password-encryption
 !
 hostname SW1
 !
 boot-start-marker
 boot-end-marker
 !
 !
 enable password cisco
 !
 no aaa new-model
 clock timezone CET 1
 !
 ip cef
 no ip domain-lookup
 !
 ipv6 unicast-routing
 ipv6 cef
 vtp domain CCIE
 vtp mode transparent
 !
 !
 !
 spanning-tree mode pvst
 spanning-tree extend system-id
 !
 vlan internal allocation policy ascending
 !
 vlan 11 
 !
 ! 
 !
 !
 !
 !
 !
 interface Loopback0
  ip address 6.6.7.7 255.255.255.255
 !
 interface Ethernet0/0
  duplex auto
  shutdown
 !
 interface Ethernet0/1
  no switchport
  ip address 6.6.17.7 255.255.255.0
  duplex auto
 !
 interface Ethernet0/2
  duplex auto
 !
 interface Ethernet0/3
  duplex auto
 !
 interface Ethernet1/0
  switchport access vlan 20
  switchport mode access
  duplex auto
 !
 interface Ethernet1/1
  switchport access vlan 5
  switchport mode access
  duplex auto
 !
 interface Ethernet1/2
  switchport access vlan 2
  switchport mode access
  shutdown
  duplex auto
 !
 interface Ethernet1/3
  switchport access vlan 2
  switchport mode access
  duplex auto
 !
 interface Ethernet2/0
  switchport access vlan 2
  switchport mode access
  duplex auto
 !
 interface Ethernet2/1
  switchport access vlan 2
  switchport mode access
  duplex auto
 !
 interface Ethernet2/2
  switchport access vlan 40
  switchport mode access
  duplex auto
 !
 interface Ethernet2/3
  switchport access vlan 2
  switchport mode access
  shutdown
  duplex auto
 !
 interface Ethernet3/0
  switchport access vlan 10
  switchport mode access
  shutdown
  duplex auto
 !
 interface Ethernet3/1
  switchport access vlan 10
  switchport mode access
  shutdown
  duplex auto
 !
 interface Ethernet3/2
  switchport access vlan 10
  switchport mode access
  shutdown
  duplex auto
 !
 interface Ethernet3/3
  switchport access vlan 2
  switchport mode access
  shutdown
  duplex auto
 !
 interface Vlan1
  no ip address
  shutdown
 !
 interface Vlan123
  ip address 6.6.123.7 255.255.255.0
  shutdown
 !
 !
 ip forward-protocol nd
 no ip http server
 !
 !
 !
 !
 !
 control-plane
 !
 !
 line con 0
  exec-timeout 0 0
  privilege level 15
  password cisco
  logging synchronous
 line aux 0
 line vty 0 4
  privilege level 15
  password cisco
  login
  transport input all
 !
 end

我希望我已经解释得这么好了。对于那些聪明的家伙来说,这可能很简单,但我正在努力解决这个问题。

3 个答案:

答案 0 :(得分:1)

我已经编写了一个Python 2.7脚本,并且我试图让它变得健壮。我使用IOS配置文件解析器(ciscoconfparse)库来避免我自己的解析尝试中的错误。我已经给它一个命令行界面,以便查看vlan 2上的接口状态:

$ python interfaces.py --vlan 2 /path/to/ios.cfg

<强>安装

  1. 安装Python 2.7
  2. 安装cisoconfparse
  3. 将下面的脚本保存为部分.py(例如interfaces.py
  4. <强> interfaces.py

    #!/usr/bin/env python
    
    from __future__ import absolute_import
    from __future__ import division
    from __future__ import print_function
    
    from argparse import ArgumentParser
    from itertools import ifilter
    import sys
    
    from ciscoconfparse import CiscoConfParse
    
    
    INTERFACE_REGEX = 'interface'
    SWITCHPORT_REGEX = 'switchport access vlan'
    
    
    def main(argv=None):
        args = parse_argv(argv=argv)
        parse = CiscoConfParse(args.conf_path)
    
        objs = parse.find_objects_w_child(INTERFACE_REGEX, SWITCHPORT_REGEX)
        records = (Record.from_ios_object(obj) for obj in objs)
        if args.vlan:
            records = ifilter(lambda r: r.vlan == args.vlan, records)
    
        for record in sorted(records, key=lambda r: r.name):
            print(record)
    
    
    def parse_argv(argv=None):
        if argv is None:
            argv = sys.argv
        parser = ArgumentParser()
        parser.add_argument('--vlan', type=int)
        parser.add_argument('conf_path')
        return parser.parse_args(args=argv[1:])
    
    
    class Record:
        def __init__(self, name, vlan, is_shutdown):
            self.name = name
            self.vlan = vlan
            self.is_shutdown = is_shutdown
    
        def __str__(self):
            if self.is_shutdown:
                state = 'shutdown'
            else:
                state = 'running'
            return '{name} {vlan} {state}'.format(
                name=self.name,
                vlan=self.vlan,
                state=state
            )
    
        @classmethod
        def from_ios_object(cls, obj):
            tokens = obj.text.split()
            if len(tokens) != 2:
                raise ValueError('Expected 2 tokens, found ' + len(tokens))
            name = tokens[1]
            children = obj.re_search_children(SWITCHPORT_REGEX)
            if len(children) != 1:
                raise ValueError('Expected 1 matching child, found ' +
                                 len(children))
            vlan = int(children[0].re_match('(\d+)$'))
            is_shutdown = bool(obj.re_search_children('shutdown'))
            return cls(name, vlan, is_shutdown)
    
    
    if __name__ == '__main__':
        sys.exit(main())
    

答案 1 :(得分:0)

将输入的每一行存储为数组中的单独元素会使处理变得复杂。如果将所有接口定义合并到一个数组元素中,它将简化您对简单字符串搜索的查找。 AWK迷你状态机就是这样做的一种方式。

#!/bin/bash
ls *.cfg | while read config; do
    interfaces=()
    IFS=$'\n'       # We'll delimit the records with this
    count=0
    printf "\b Starting $config... \n"    
    for i in $(awk '# ^interface = start of interface def; insert delimiter, set flag.
                    /^interface Ethernet/{inside_int=1}

                    # ! = end of interface def; unset flag.
                    (/!/ && inside_int){inside_int=0; print}

                    # if flag is set, print line
                    inside_int{printf "%s ", $0}

                    ' config.cfg ); do

        # append to interfaces array
        interfaces=(${interfaces[@]} $i)

        # Create three arrays with interface data

        # Interface name
        intname[$count]=$( echo "$i}" | sed -n "s/interface \([^ ]*\).*/\1/p" )

        # Interface VLAN
        vlan[$count]=$( echo "$i}" | sed -n 's/interface.*switchport access vlan \([^ ]*\).*/\1/p' )

        # Interface up/down (0/1) status
        isdown[$count]=$( echo "$i}" | grep -c shutdown )

        ((count++))
    done

    # Loop and display values.
    for (( i=0; i<${#interfaces[@]}; i++ )); do
        echo -e "Int:${intname[$i]}\tvlan:${vlan[$i]}\tisdown:${isdown[$i]}"
    done
done

${intname[@]}${vlan[@]}${isdown[@]}数组包含您要查找的各个值。 ${interfaces[@]}数组包含每个接口定义作为单独的元素,可以对其他数据进行字符串搜索。

答案 2 :(得分:0)

您不应尝试使用bash脚本解析分层文本文件(如Cisco IOS配置)...使用预制配置解析库...

改进@ PeterSutton的答案...... CiscoConfParse支持自动vlan解析,如果你用factory=True进行解析(是的,我知道这仍然没有记录,但你可以找到所有可能的解析ciscoconfparse/models_cisco.py来源中的值...)

解析接口名称,switchport状态和访问vlan编号的代码就这么简单......

from ciscoconfparse import CiscoConfParse
from prettytable import PrettyTable

parse = CiscoConfParse('config.text', factory=True)
table = PrettyTable(['Intf Name', 'Switchport?', 'Access Vlan (0 is no vlan)'])
for intf_obj in parse.find_objects('^interface'):
    table.add_row([intf_obj.name, intf_obj.is_switchport, intf_obj.access_vlan])

print table

当你运行它时,你得到一个文本表......

(py27_test)[mpenning@tsunami ~]$ python example.py 
+-------------+-------------+----------------------------+
|  Intf Name  | Switchport? | Access Vlan (0 is no vlan) |
+-------------+-------------+----------------------------+
|  Loopback0  |    False    |             0              |
| Ethernet0/0 |    False    |             0              |
| Ethernet0/1 |    False    |             0              |
| Ethernet0/2 |    False    |             0              |
| Ethernet0/3 |    False    |             0              |
| Ethernet1/0 |     True    |             20             |
| Ethernet1/1 |     True    |             5              |
| Ethernet1/2 |     True    |             2              |
| Ethernet1/3 |     True    |             2              |
| Ethernet2/0 |     True    |             2              |
| Ethernet2/1 |     True    |             2              |
| Ethernet2/2 |     True    |             40             |
| Ethernet2/3 |     True    |             2              |
| Ethernet3/0 |     True    |             10             |
| Ethernet3/1 |     True    |             10             |
| Ethernet3/2 |     True    |             10             |
| Ethernet3/3 |     True    |             2              |
|    Vlan1    |    False    |             0              |
|   Vlan123   |    False    |             0              |
+-------------+-------------+----------------------------+
(py27_test)[mpenning@tsunami ~]$

您可以使用Inline::Pythonciscoconfparse嵌入到perl脚本中......但是您仍然需要在python中编写,因此我不确定任务的重点是什么这很简单。


免责声明:我是CiscoConfParse的作者