使用捕获的值作为行标识符
Use a captured value as row identifier
我需要解析此原始数据以便对其进行处理:
Port Align-Err FCS-Err Xmit-Err Rcv-Err UnderSize OutDiscards
Gi0/1 1 2 3 4 5 6
Gi0/2 11 12 13 14 15 16
Port Single-Col Multi-Col Late-Col Excess-Col Carri-Sen Runts Giants
Gi0/1 1 2 3 4 5 6 7
Gi0/2 111 122 133 144 155 166 177
为此,我使用了 TextFSM。
我想要这个输出:
['Gi0/1', '1', '2', '3', '4', '5', '6', '1', '2', '3', '4', '5', '6', '7']
['Gi0/2', '11', '12', '13', '14', '15', '16', '111', '112', '113', '114', '115', '116', '117']
我写的第一个模板就是这个:
Value PORT (\S+(/\d+)?)
Value ALIGNERR (\d+)
Value FCSERR (\d+)
Value XMITERR (\d+)
Value RCVERR (\d+)
Value UNDERSIZE (\d+)
Value OUTDISCARDS (\d+)
Value SINGLECOL (\d+)
Value MULTICOL (\d+)
Value LATECOL (\d+)
Value EXCESSCOL (\d+)
Value CARRISEN (\d+)
Value RUNTS (\d+)
Value GIANTS (\d+)
Start
^Port\s+Align-Err.* -> FIRST
^Port\s+Single-Col.* -> SECOND
FIRST
^${PORT}\s+${ALIGNERR}\s+${FCSERR}\s+${XMITERR}\s+${RCVERR}\s+${UNDERSIZE}\s+${OUTDISCARDS} -> Continue.Record
SECOND
^${PORT}\s+${SINGLECOL}\s+${MULTICOL}\s+${LATECOL}\s+${EXCESSCOL}\s+${CARRISEN}\s+${RUNTS}\s+${GIANTS} -> Record
然而,输出不正确:
['Gi0/1', '1', '2', '3', '4', '5', '6', '', '', '', '', '', '', '']
['Gi0/2', '11', '12', '13', '14', '15', '16', '', '', '', '', '', '', '']
['Gi0/1', '1', '2', '3', '4', '5', '6', '', '', '', '', '', '', '']
['Gi0/2', '111', '122', '133', '144', '155', '166', '', '', '', '', '', '', '']
我在论坛上找到了 post,它给出了纯正则表达式的解决方案:
当我根据我的需要调整它时,我有一个匹配我需要的东西:https://regex101.com/r/DY0Meb/6
但是,我无法在 TextFSM 模板中翻译它,它失败了。
这是我的模板:
Value PORT (\S+(/\d+)?)
Value ALIGNERR (\d+)
Value FCSERR (\d+)
Value XMITERR (\d+)
Value RCVERR (\d+)
Value UNDERSIZE (\d+)
Value OUTDISCARDS (\d+)
Value SINGLECOL (\d+)
Value MULTICOL (\d+)
Value LATECOL (\d+)
Value EXCESSCOL (\d+)
Value CARRISEN (\d+)
Value RUNTS (\d+)
Value GIANTS (\d+)
Start
^${PORT}\s+${ALIGNERR}\s+${FCSERR}\s+${XMITERR}\s+${RCVERR}\s+${UNDERSIZE}\s+${OUTDISCARDS}(?=.*\s+${SINGLECOL}\s+${MULTICOL}\s+${LATECOL}\s+${EXCESSCOL}\s+${CARRISEN}\s+${RUNTS}\s+${GIANTS}) -> Record
关于为什么我没有任何匹配项的任何线索?
我是正则表达式的初学者,我似乎找不到解决方案...
非常欢迎任何帮助:)。
提前致谢!
终于如愿以偿
我的团队希望使用 Ansible 进行格式化,所以我不得不即兴创作。
我为此使用了 ntc-ansible。
在 NTC Slack 成员的帮助下,我终于让它运行起来了。这是我想出的:
TextFSM 存储库中很少记录的一项功能是,您可以在索引文件中组合两个共享公共 "Key" 属性的模板。
所以我创建了两个模板:
Value Key PORT (\S+(/\d+)+)
Value ALIGNERR (\d+)
Value FCSERR (\d+)
Value XMITERR (\d+)
Value RCVERR (\d+)
Value UNDERSIZE (\d+)
Value OUTDISCARDS (\d+)
Start
^Port\s+Align-Err.* -> Begin
Begin
^${PORT}\s+${ALIGNERR}\s+${FCSERR}\s+${XMITERR}\s+${RCVERR}\s+${UNDERSIZE}\s+${OUTDISCARDS} -> Record
^Port\s+Single-Col.* -> End
并且:
Value Key PORT (\S+(/\d+)+)
Value SINGLECOL (\d+)
Value MULTICOL (\d+)
Value LATECOL (\d+)
Value EXCESSCOL (\d+)
Value CARRISEN (\d+)
Value RUNTS (\d+)
Value GIANTS (\d+)
Start
^Port\s+Single-Col.* -> Begin
Begin
^${PORT}\s+${SINGLECOL}\s+${MULTICOL}\s+${LATECOL}\s+${EXCESSCOL}\s+${CARRISEN}\s+${RUNTS}\s+${GIANTS} -> Record
然后,我创建了一个包含以下内容的索引文件:
Template, Hostname, Vendor, Command
show_int_counter_errors1.template:show_int_counter_errors2.template, .*, cisco_ios, sh[[ow]] int[[erfaces]] cou[[nter]] er[[rors]]
您可以在 Python 中使用这个小脚本对其进行测试:
import textfsm
import sys
from textfsm import clitable
# Define Input Data
input_data = sys.stdin.read()
# Initialise CliTable with the content of the 'index' file.
cli_table = clitable.CliTable('index', '.')
# Firstly we will use attributes to match a 'show version' command on a Cisco device.
attributes = {'Command': sys.argv[1], 'Vendor': 'cisco_ios'}
# Parse Data
cli_table.ParseCmd(input_data, attributes)
print(cli_table)
要启动它,只需使用这个命令:
python3 test_table.py 'show interface counter errors' < show_int_counter_errors.txt
要在Ansible中使用,安装ntc-ansible后,创建一个'templates'目录,将索引文件和模板文件放入其中,并在playbook中指定目录路径:
- hosts: all
connection: local
gather_facts: no
tasks:
- name: Formatting the errors
ntc_show_command:
connection: ssh
platform: cisco_ios
command: 'show interfaces counter errors'
use_templates: True
template_dir: 'PATH/TO/TEMPLATES/DIRECTORY'
host: "{{ ansible_host }}"
username: "{{ ansible_user }}"
password: "{{ ansible_password }}"
register: interface_errors
- name: Display the registered variable
debug:
var: interface_errors
希望这可以帮助任何人:)。
有一种更简单的方法:
from ttp import ttp
import pprint
data = """
Port Align-Err FCS-Err Xmit-Err Rcv-Err UnderSize OutDiscards
Gi0/1 1 2 3 4 5 6
Gi0/2 11 12 13 14 15 16
Port Single-Col Multi-Col Late-Col Excess-Col Carri-Sen Runts Giants
Gi0/1 1 2 3 4 5 6 7
Gi0/2 111 122 133 144 155 166 177
"""
template = """
<group name="{{ interface }}*">
{{ interface | exclude("Port") }} {{ counters | ROW | resub("\s+", ",", 200) | split(",") }}
</group>
"""
parser = ttp(data, template)
parser.parse()
res = parser.result()[0][0]
# res is this now:
# {'Gi0/1': [{'counters': ['1', '2', '3', '4', '5', '6']},
# {'counters': ['1', '2', '3', '4', '5', '6', '7']}],
# 'Gi0/2': [{'counters': ['11', '12', '13', '14', '15', '16']},
# {'counters': ['111', '122', '133', '144', '155', '166', '177']}]}
ret = []
for interface, counters in res.items():
ret.append([interface])
for i in counters:
ret[-1] += list(i.values())[0]
pprint.pprint(ret, width=100)
# will print:
# [['Gi0/1', '1', '2', '3', '4', '5', '6', '1', '2', '3', '4', '5', '6', '7'],
# ['Gi0/2', '11', '12', '13', '14', '15', '16', '111', '122', '133', '144', '155', '166', '177']]
TTP - 是我创建的一个库,用于使上述任务的解决方案看起来更简单。
我需要解析此原始数据以便对其进行处理:
Port Align-Err FCS-Err Xmit-Err Rcv-Err UnderSize OutDiscards
Gi0/1 1 2 3 4 5 6
Gi0/2 11 12 13 14 15 16
Port Single-Col Multi-Col Late-Col Excess-Col Carri-Sen Runts Giants
Gi0/1 1 2 3 4 5 6 7
Gi0/2 111 122 133 144 155 166 177
为此,我使用了 TextFSM。
我想要这个输出:
['Gi0/1', '1', '2', '3', '4', '5', '6', '1', '2', '3', '4', '5', '6', '7']
['Gi0/2', '11', '12', '13', '14', '15', '16', '111', '112', '113', '114', '115', '116', '117']
我写的第一个模板就是这个:
Value PORT (\S+(/\d+)?)
Value ALIGNERR (\d+)
Value FCSERR (\d+)
Value XMITERR (\d+)
Value RCVERR (\d+)
Value UNDERSIZE (\d+)
Value OUTDISCARDS (\d+)
Value SINGLECOL (\d+)
Value MULTICOL (\d+)
Value LATECOL (\d+)
Value EXCESSCOL (\d+)
Value CARRISEN (\d+)
Value RUNTS (\d+)
Value GIANTS (\d+)
Start
^Port\s+Align-Err.* -> FIRST
^Port\s+Single-Col.* -> SECOND
FIRST
^${PORT}\s+${ALIGNERR}\s+${FCSERR}\s+${XMITERR}\s+${RCVERR}\s+${UNDERSIZE}\s+${OUTDISCARDS} -> Continue.Record
SECOND
^${PORT}\s+${SINGLECOL}\s+${MULTICOL}\s+${LATECOL}\s+${EXCESSCOL}\s+${CARRISEN}\s+${RUNTS}\s+${GIANTS} -> Record
然而,输出不正确:
['Gi0/1', '1', '2', '3', '4', '5', '6', '', '', '', '', '', '', '']
['Gi0/2', '11', '12', '13', '14', '15', '16', '', '', '', '', '', '', '']
['Gi0/1', '1', '2', '3', '4', '5', '6', '', '', '', '', '', '', '']
['Gi0/2', '111', '122', '133', '144', '155', '166', '', '', '', '', '', '', '']
我在论坛上找到了 post,它给出了纯正则表达式的解决方案:
当我根据我的需要调整它时,我有一个匹配我需要的东西:https://regex101.com/r/DY0Meb/6
但是,我无法在 TextFSM 模板中翻译它,它失败了。 这是我的模板:
Value PORT (\S+(/\d+)?)
Value ALIGNERR (\d+)
Value FCSERR (\d+)
Value XMITERR (\d+)
Value RCVERR (\d+)
Value UNDERSIZE (\d+)
Value OUTDISCARDS (\d+)
Value SINGLECOL (\d+)
Value MULTICOL (\d+)
Value LATECOL (\d+)
Value EXCESSCOL (\d+)
Value CARRISEN (\d+)
Value RUNTS (\d+)
Value GIANTS (\d+)
Start
^${PORT}\s+${ALIGNERR}\s+${FCSERR}\s+${XMITERR}\s+${RCVERR}\s+${UNDERSIZE}\s+${OUTDISCARDS}(?=.*\s+${SINGLECOL}\s+${MULTICOL}\s+${LATECOL}\s+${EXCESSCOL}\s+${CARRISEN}\s+${RUNTS}\s+${GIANTS}) -> Record
关于为什么我没有任何匹配项的任何线索? 我是正则表达式的初学者,我似乎找不到解决方案...
非常欢迎任何帮助:)。 提前致谢!
终于如愿以偿
我的团队希望使用 Ansible 进行格式化,所以我不得不即兴创作。
我为此使用了 ntc-ansible。
在 NTC Slack 成员的帮助下,我终于让它运行起来了。这是我想出的:
TextFSM 存储库中很少记录的一项功能是,您可以在索引文件中组合两个共享公共 "Key" 属性的模板。
所以我创建了两个模板:
Value Key PORT (\S+(/\d+)+)
Value ALIGNERR (\d+)
Value FCSERR (\d+)
Value XMITERR (\d+)
Value RCVERR (\d+)
Value UNDERSIZE (\d+)
Value OUTDISCARDS (\d+)
Start
^Port\s+Align-Err.* -> Begin
Begin
^${PORT}\s+${ALIGNERR}\s+${FCSERR}\s+${XMITERR}\s+${RCVERR}\s+${UNDERSIZE}\s+${OUTDISCARDS} -> Record
^Port\s+Single-Col.* -> End
并且:
Value Key PORT (\S+(/\d+)+)
Value SINGLECOL (\d+)
Value MULTICOL (\d+)
Value LATECOL (\d+)
Value EXCESSCOL (\d+)
Value CARRISEN (\d+)
Value RUNTS (\d+)
Value GIANTS (\d+)
Start
^Port\s+Single-Col.* -> Begin
Begin
^${PORT}\s+${SINGLECOL}\s+${MULTICOL}\s+${LATECOL}\s+${EXCESSCOL}\s+${CARRISEN}\s+${RUNTS}\s+${GIANTS} -> Record
然后,我创建了一个包含以下内容的索引文件:
Template, Hostname, Vendor, Command
show_int_counter_errors1.template:show_int_counter_errors2.template, .*, cisco_ios, sh[[ow]] int[[erfaces]] cou[[nter]] er[[rors]]
您可以在 Python 中使用这个小脚本对其进行测试:
import textfsm
import sys
from textfsm import clitable
# Define Input Data
input_data = sys.stdin.read()
# Initialise CliTable with the content of the 'index' file.
cli_table = clitable.CliTable('index', '.')
# Firstly we will use attributes to match a 'show version' command on a Cisco device.
attributes = {'Command': sys.argv[1], 'Vendor': 'cisco_ios'}
# Parse Data
cli_table.ParseCmd(input_data, attributes)
print(cli_table)
要启动它,只需使用这个命令:
python3 test_table.py 'show interface counter errors' < show_int_counter_errors.txt
要在Ansible中使用,安装ntc-ansible后,创建一个'templates'目录,将索引文件和模板文件放入其中,并在playbook中指定目录路径:
- hosts: all
connection: local
gather_facts: no
tasks:
- name: Formatting the errors
ntc_show_command:
connection: ssh
platform: cisco_ios
command: 'show interfaces counter errors'
use_templates: True
template_dir: 'PATH/TO/TEMPLATES/DIRECTORY'
host: "{{ ansible_host }}"
username: "{{ ansible_user }}"
password: "{{ ansible_password }}"
register: interface_errors
- name: Display the registered variable
debug:
var: interface_errors
希望这可以帮助任何人:)。
有一种更简单的方法:
from ttp import ttp
import pprint
data = """
Port Align-Err FCS-Err Xmit-Err Rcv-Err UnderSize OutDiscards
Gi0/1 1 2 3 4 5 6
Gi0/2 11 12 13 14 15 16
Port Single-Col Multi-Col Late-Col Excess-Col Carri-Sen Runts Giants
Gi0/1 1 2 3 4 5 6 7
Gi0/2 111 122 133 144 155 166 177
"""
template = """
<group name="{{ interface }}*">
{{ interface | exclude("Port") }} {{ counters | ROW | resub("\s+", ",", 200) | split(",") }}
</group>
"""
parser = ttp(data, template)
parser.parse()
res = parser.result()[0][0]
# res is this now:
# {'Gi0/1': [{'counters': ['1', '2', '3', '4', '5', '6']},
# {'counters': ['1', '2', '3', '4', '5', '6', '7']}],
# 'Gi0/2': [{'counters': ['11', '12', '13', '14', '15', '16']},
# {'counters': ['111', '122', '133', '144', '155', '166', '177']}]}
ret = []
for interface, counters in res.items():
ret.append([interface])
for i in counters:
ret[-1] += list(i.values())[0]
pprint.pprint(ret, width=100)
# will print:
# [['Gi0/1', '1', '2', '3', '4', '5', '6', '1', '2', '3', '4', '5', '6', '7'],
# ['Gi0/2', '11', '12', '13', '14', '15', '16', '111', '122', '133', '144', '155', '166', '177']]
TTP - 是我创建的一个库,用于使上述任务的解决方案看起来更简单。