【问题标题】:Need help parsing Cisco output需要帮助解析 Cisco 输出
【发布时间】:2016-06-22 05:00:22
【问题描述】:

我在尝试解析路由器的 mrib 表时遇到了一些问题。我已经能够解析出其中的一些但有问题。例如我有以下输出:

(192.168.1.1,232.0.6.8) RPF nbr: 55.44.23.1 Flags: RPF
  Up: 4w1d
  Incoming Interface List
    TenGigE0/0/0/1 Flags: A, Up: 4w1d
  Outgoing Interface List
    TenGigE0/0/0/10 Flags: A, Up: 4w1d

(192.168.55.3,232.0.10.69) RPF nbr: 66.76.44.130 Flags: RPF
  Up: 4w1d
  Incoming Interface List
    TenGigE0/0/0/0 Flags: A, Up: 4w1d
    TenGigE0/1/0/0 Flags: A, Up: 4w1d
    TenGigE0/2/0/0 Flags: A, Up: 4w1d
  Outgoing Interface List
    TenGigE0/0/0/10 Flags: A, Up: 4w1d
    TenGigE0/3/0/0 Flags: A, Up: 4w1d
    TenGigE0/4/0/0 Flags: A, Up: 4w1d

我正在尝试使用上述输出构建数据结构。为了清楚起见,我希望它看起来像这样:

{'192.168.1.1,232.0.6.8': {'incoming': ['TenGigE0/0/0/1'],
                           'outgoing': ['TenGigE0/0/0/10']}}

以上听起来很简单。我遇到的主要问题之一是第二个区块。我试图想办法在传入和传出接口之后迭代接口。

不一定要求提供代码,但执行此类操作的最佳方法是什么?

【问题讨论】:

  • 我只想说在 python 中“做这样的事情的最好方法”是TextFSM

标签: python regex parsing ciscoconfparse


【解决方案1】:

好吧,如果您能够在Python 中使用较新的regex module,您可以定义子模式并使用以下方法:

  1. 在开头为 IP 地址定义子模式
  2. ...以及传入和传出接口
  3. 分别解析接口
  4. 见a demo on regex101.com。


定义子模式

为Incoming 和Outgoing Interface 字符串、IP adress 和结尾定义子模式。

(?(DEFINE)
    (?<ips>[^()]+)
    (?<incoming>Incoming\ Interface \ List)
    (?<outgoing>Outgoing\ Interface \ List)
    (?<end>^$|\Z)
)

把正则表达式放在一起

将 IP 部分锚定到行首,并为传入/传出部分使用带有负前瞻的tempered greedy令牌。

    ^\((?P<ip>(?&ips))\)
    (?:(?!(?&incoming))[\s\S]+?)
    (?&incoming)[\r\n]
    (?P<in>(?!(?&outgoing))[\s\S]+?) # tempered greedy token
    (?&outgoing)[\r\n]
    (?P<out>(?!^$)[\s\S]+?)
    (?&end)

解析传入/传出部分

由于您只需要接口类型/名称,因此您可以简单地提出:

TenGig\S+ # TenGig, followed by anything NOT a whitespace

提示

您实际上并不需要定义子模式,但是您需要重复自己很多次(因为 neg.lookaheads)。所以如果你需要坚持原来的 re 模块,你也可以很好地使用它。

粘在一起

在代码中粘合在一起,这将是:

import regex as re

string = """
(192.168.1.1,232.0.6.8) RPF nbr: 55.44.23.1 Flags: RPF
  Up: 4w1d
  Incoming Interface List
    TenGigE0/0/0/1 Flags: A, Up: 4w1d
  Outgoing Interface List
    TenGigE0/0/0/10 Flags: A, Up: 4w1d

(192.168.55.3,232.0.10.69) RPF nbr: 66.76.44.130 Flags: RPF
  Up: 4w1d
  Incoming Interface List
    TenGigE0/0/0/0 Flags: A, Up: 4w1d
    TenGigE0/1/0/0 Flags: A, Up: 4w1d
    TenGigE0/2/0/0 Flags: A, Up: 4w1d
  Outgoing Interface List
    TenGigE0/0/0/10 Flags: A, Up: 4w1d
    TenGigE0/3/0/0 Flags: A, Up: 4w1d
    TenGigE0/4/0/0 Flags: A, Up: 4w1d
"""

rx = re.compile(r"""
            (?(DEFINE)
                (?<ips>[^()]+)
                (?<incoming>Incoming\ Interface \ List)
                (?<outgoing>Outgoing\ Interface \ List)
                (?<end>^$|\Z)
            )
            ^\((?P<ip>(?&ips))\)
            (?:(?!(?&incoming))[\s\S]+?)
            (?&incoming)[\r\n]
            (?P<in>(?!(?&outgoing))[\s\S]+?)
            (?&outgoing)[\r\n]
            (?P<out>(?!^$)[\s\S]+?)
            (?&end)
""", re.MULTILINE|re.VERBOSE)

rxiface = re.compile(r'TenGig\S+')

result = dict()
for match in rx.finditer(string):
    key = match.group('ip')
    incoming = rxiface.findall(match.group('in'))
    outgoing = rxiface.findall(match.group('out'))

    result[key] = {'incoming': incoming, 'outgoing': outgoing}

print result
# {'192.168.1.1,232.0.6.8': {'outgoing': ['TenGigE0/0/0/10'], 'incoming': ['TenGigE0/0/0/1']}, '192.168.55.3,232.0.10.69': {'outgoing': ['TenGigE0/0/0/10', 'TenGigE0/3/0/0', 'TenGigE0/4/0/0'], 'incoming': ['TenGigE0/0/0/0', 'TenGigE0/1/0/0', 'TenGigE0/2/0/0']}}

【讨论】:

  • 哇!这太棒了。这正是我所需要的,感谢您的指导(和代码)。我今天会玩这个。我肯定从你所说的较新的 RE 中学到了一些东西。如果出现任何问题,我们会更新您或代码。
  • 完美运行。我必须在 rxiface 表达式中添加一些不同的接口类型,但我没有在问题中说明这一点。再次感谢您。
  • @JaredHenry:不用担心,很高兴为您提供帮助。
【解决方案2】:

假设您的输入完整且格式正确:

matcher = re.compile(
    r'\((?P<range>[^\)]+)\)|'
    r'(?P<incoming>\s+Incoming Interface List)|'
    r'(?P<outgoing>\s+Outgoing Interface List)|'
    r'\s+(?P<interface>TenGigE0[^\s]+)'
)

with open('router_table.txt', 'r') as f:
    routing_table = []
    current_range = ''
    direction = ''
    for line in f:
        match = matcher.search(line)
        if match:
            if match.group('interface'):
                routing_table[-1][current_range][direction].append(match.group('interface'))
            if match.group('range'):
                current_range = match.group('range')
                routing_table.append(
                    {
                        current_range: {
                            'incoming': [],
                            'outgoing': []
                        }
                    }
                )
            if match.group('incoming'):
                direction = 'incoming'
            if match.group('outgoing'):
                direction = 'outgoing'

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-10-23
    • 2011-08-15
    • 1970-01-01
    • 2016-07-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-02-26
    相关资源
    最近更新 更多