上篇文章中大致介绍了下textFSM的语法并且进行了一些简单的说明,这篇文章是一些简单的案例来帮助大家更好的理解一些特殊的用法。
测试环境
系统:windows自带ubuntu子系统
Filldown关键字用法
下面是一段juniper设备上show chassis fpc的output,首先看下没有Filldown关键字对文本的匹配结果:
#test_parse.py
import textfsm
import os
show_chassis = '''
lcc0-re0:
--------------------------------------------------------------------------
Temp CPU Utilization (%) Memory Utilization (%)
Slot State (C) Total Interrupt DRAM (MB) Heap Buffer
0 Online 24 8 1 512 16 52
1 Online 23 7 1 256 36 53
2 Online 23 5 1 256 36 49
3 Online 21 7 1 256 36 49
4 Empty
5 Empty
6 Empty
7 Empty
lcc1-re1:
--------------------------------------------------------------------------
Temp CPU Utilization (%) Memory Utilization (%)
Slot State (C) Total Interrupt DRAM (MB) Heap Buffer
0 Online 20 9 1 256 36 50
1 Online 20 13 0 256 36 49
2 Online 21 6 1 256 36 49
3 Online 20 6 0 256 36 49
4 Online 18 5 0 256 35 49
5 Empty
6 Empty
7 Empty'''
with open('../templates/show_chassis.template') as template:
fsm = textfsm.TextFSM(template)
result = fsm.ParseText(show_chassis)
print(fsm.header)
for res in result:
print(res)
#show_chassis.template
Value Chassis (\S+)
Value Slot (\d)
Value State (\w+)
Value Temperature (\d+)
Value DRAM (\d+)
Value Buffer (\d+)
Start
^${Chassis}:
^\s+${Slot}\s+${State}\s+${Temperature}\s+\d+\s+\d+\s+${DRAM}\s+\d+\s+${Buffer} -> Record
^\s+${Slot}\s+${State} -> Record
#输出:
['Chassis', 'Slot', 'State', 'Temperature', 'DRAM', 'Buffer']
['lcc0-re0', '0', 'Online', '24', '512', '52']
['', '1', 'Online', '23', '256', '53']
['', '2', 'Online', '23', '256', '49']
['', '3', 'Online', '21', '256', '49']
['', '4', 'Empty', '', '', '']
['', '5', 'Empty', '', '', '']
['', '6', 'Empty', '', '', '']
['', '7', 'Empty', '', '', '']
['lcc1-re1', '0', 'Online', '20', '256', '50']
['', '1', 'Online', '20', '256', '49']
['', '2', 'Online', '21', '256', '49']
['', '3', 'Online', '20', '256', '49']
['', '4', 'Online', '18', '256', '49']
['', '5', 'Empty', '', '', '']
['', '6', 'Empty', '', '', '']
['', '7', 'Empty', '', '', '']
很明显这个输出不是我们想要的结果,我们希望每行都可以标识出chassis number。下面我们加上Filldown关键字再看下输出的结果。在Chassis这个变量中我们加上option选项中的Filldown,顾名思义向下填充。
#show_chassis.template
Value Filldown Chassis (\S+)
Value Slot (\d)
Value State (\w+)
Value Temperature (\d+)
Value DRAM (\d+)
Value Buffer (\d+)
Start
^${Chassis}:
^\s+${Slot}\s+${State}\s+${Temperature}\s+\d+\s+\d+\s+${DRAM}\s+\d+\s+${Buffer} -> Record
^\s+${Slot}\s+${State} -> Record
#输出
['Chassis', 'Slot', 'State', 'Temperature', 'DRAM', 'Buffer']
['lcc0-re0', '0', 'Online', '24', '512', '52']
['lcc0-re0', '1', 'Online', '23', '256', '53']
['lcc0-re0', '2', 'Online', '23', '256', '49']
['lcc0-re0', '3', 'Online', '21', '256', '49']
['lcc0-re0', '4', 'Empty', '', '', '']
['lcc0-re0', '5', 'Empty', '', '', '']
['lcc0-re0', '6', 'Empty', '', '', '']
['lcc0-re0', '7', 'Empty', '', '', '']
['lcc1-re1', '0', 'Online', '20', '256', '50']
['lcc1-re1', '1', 'Online', '20', '256', '49']
['lcc1-re1', '2', 'Online', '21', '256', '49']
['lcc1-re1', '3', 'Online', '20', '256', '49']
['lcc1-re1', '4', 'Online', '18', '256', '49']
['lcc1-re1', '5', 'Empty', '', '', '']
['lcc1-re1', '6', 'Empty', '', '', '']
['lcc1-re1', '7', 'Empty', '', '', '']
['lcc1-re1', '', '', '', '', '']
这里的输出和我们的期望值就很近了,但是多出来了奇怪的一行。可以通过Required关键字来进行优化。
Required关键字用法
Required表示必须的,就是本行除了Filldown变量意外,添加Required关键字的值必须匹配到值才可以返回结果。下面我在Slot和State前加上Required再看下输出结果。如下的结果就非常符合我们的预期了。
#show_chassis.template
Value Filldown Chassis (\S+)
Value Required Slot (\d)
Value Required State (\w+)
Value Temperature (\d+)
Value DRAM (\d+)
Value Buffer (\d+)
Start
^${Chassis}:
^\s+${Slot}\s+${State}\s+${Temperature}\s+\d+\s+\d+\s+${DRAM}\s+\d+\s+${Buffer} -> Record
^\s+${Slot}\s+${State} -> Record
['Chassis', 'Slot', 'State', 'Temperature', 'DRAM', 'Buffer']
['lcc0-re0', '0', 'Online', '24', '512', '52']
['lcc0-re0', '1', 'Online', '23', '256', '53']
['lcc0-re0', '2', 'Online', '23', '256', '49']
['lcc0-re0', '3', 'Online', '21', '256', '49']
['lcc0-re0', '4', 'Empty', '', '', '']
['lcc0-re0', '5', 'Empty', '', '', '']
['lcc0-re0', '6', 'Empty', '', '', '']
['lcc0-re0', '7', 'Empty', '', '', '']
['lcc1-re1', '0', 'Online', '20', '256', '50']
['lcc1-re1', '1', 'Online', '20', '256', '49']
['lcc1-re1', '2', 'Online', '21', '256', '49']
['lcc1-re1', '3', 'Online', '20', '256', '49']
['lcc1-re1', '4', 'Online', '18', '256', '49']
['lcc1-re1', '5', 'Empty', '', '', '']
['lcc1-re1', '6', 'Empty', '', '', '']
['lcc1-re1', '7', 'Empty', '', '', '']
List关键字
List关键字可以将某一列定义为一个列表,将返回的多个值存储在列表中。看下面的例子来替换List关键字和Continue关键字的作用。
#test_parse.py
import textfsm
import os
route_list = '''
Destination Gateway Dist/Metric Last Change
----------- ------- ----------- -----------
B EX 0.0.0.0/0 via 192.0.2.73 20/100 4w0d
via 192.0.2.201
via 192.0.2.202
via 192.0.2.74
B IN 192.0.2.76/30 via 203.0.113.183 200/100 4w2d
B IN 192.0.2.204/30 via 203.0.113.183 200/100 4w2d
B IN 192.0.2.80/30 via 203.0.113.183 200/100 4w2d
B IN 192.0.2.208/30 via 203.0.113.183 200/100 4w2d
'''
with open('../templates/route_list.template') as template:
fsm = textfsm.TextFSM(template)
result = fsm.ParseText(route_list)
print(fsm.header)
for res in result:
print(res)
#route_list.template
Value Protocol (\S)
Value Type (\S\S)
Value Required Prefix (\S+)
Value Gateway (\S+)
Value Distance (\d+)
Value Metric (\d+)
Value LastChange (\S+)
Start
^.*----- -> Routes
Routes
^ ${Protocol} ${Type} ${Prefix}\s+via ${Gateway}\s+${Distance}/${Metric}\s+${LastChange} -> Record
#输出:
['Protocol', 'Type', 'Prefix', 'Gateway', 'Distance', 'Metric', 'LastChange']
['B', 'EX', '0.0.0.0/0', '192.0.2.73', '20', '100', '4w0d']
['B', 'IN', '192.0.2.76/30', '203.0.113.183', '200', '100', '4w2d']
['B', 'IN', '192.0.2.204/30', '203.0.113.183', '200', '100', '4w2d']
['B', 'IN', '192.0.2.80/30', '203.0.113.183', '200', '100', '4w2d']
['B', 'IN', '192.0.2.208/30', '203.0.113.183', '200', '100', '4w2d']
这个输出的结果明显不是我们的预期的,缺省路由的下一跳值匹配到了一个。现在 我们再对template文件做下改动,加上List和Continue关键字。List关键字很好理解就是将Gateway这一列声明为List格式。我们再看下Continue的文档说明,保留当前行并且不再重新匹配State的第一个规则,继续运行规则好像匹配没有发生。
image.png
Value Protocol (\S)
Value Type (\S\S)
Value Prefix (\S+)
Value List Gateway (\S+)
Value Distance (\d+)
Value Metric (\d+)
Value LastChange (\S+)
Start
^.*----- -> Routes
Routes
^ \S \S\S -> Continue.Record
^ ${Protocol} ${Type} ${Prefix}\s+via ${Gateway}\s+${Distance}/${Metric}\s+${LastChange}
^\s+via ${Gateway}
Continue这行的 \S \S\S匹配到第一行时,此时触发Continue机制,后续文本继续向下匹配并进行记录,直到出现下一个可以匹配到 \S \S\S再开始进行下一个Record。
B EX 0.0.0.0/0 via 192.0.2.73 20/100 4w0d
最后的执行结果
['Protocol', 'Type', 'Prefix', 'Gateway', 'Distance', 'Metric', 'LastChange']
['B', 'EX', '0.0.0.0/0', ['192.0.2.73', '192.0.2.201', '192.0.2.202', '192.0.2.74'], '20', '100', '4w0d']
['B', 'IN', '192.0.2.76/30', ['203.0.113.183'], '200', '100', '4w2d']
['B', 'IN', '192.0.2.204/30', ['203.0.113.183'], '200', '100', '4w2d']
['B', 'IN', '192.0.2.80/30', ['203.0.113.183'], '200', '100', '4w2d']
['B', 'IN', '192.0.2.208/30', ['203.0.113.183'], '200', '100', '4w2d']
还有一个很好的案例大家也可以看下,题主自己解决的问题,不过很实用的一个场景。
https://www.pythonheidong.com/blog/article/509484/7a82ca483a323b79066d/
还有一个很好的正则表达式练习的网站:https://regex101.com/
参考文档
textFSM官方文档
https://github.com/google/textfsm/wiki/Code-Lab
网友评论