Приклади роботи з файлами¶
У цьому підрозділі розглядається робота з файлами та поєднуються теми: файли, цикли та умови.
При обробці виводу команд чи конфігурації часто потрібно буде записати підсумкові дані у словник. Не завжди очевидно, як обробляти виводу команд і як загалом підходити до розбору виводу на частини. У цьому підрозділі розглядаються кілька прикладів, із зростаючим рівнем складності.
Розбір виводу стовпцями¶
У цьому прикладі розбиратиметься вивід команди sh ip int br. З виводу команди нам треба отримати відповідність ім'я інтерфейсу – IP-адресу. Тобто ім'я інтерфейсу – це ключ словника, а IP-адреса – значення. При цьому, відповідність треба робити тільки для тих інтерфейсів, у яких призначено IP-адресу.
Приклад виводу команди sh ip int br (файл sh_ip_int_br.txt):
R1#show ip interface brief
Interface IP-Address OK? Method Status Protocol
FastEthernet0/0 15.0.15.1 YES manual up up
FastEthernet0/1 10.0.12.1 YES manual up up
FastEthernet0/2 10.0.13.1 YES manual up up
FastEthernet0/3 unassigned YES unset up down
Loopback0 10.1.1.1 YES manual up up
Loopback100 100.0.0.1 YES manual up up
Файл working_with_dict_example_1.py:
result = {}
with open('sh_ip_int_br.txt') as f:
for line in f:
line_list = line.split()
if line_list and line_list[1][0].isdigit():
interface = line_list[0]
address = line_list[1]
result[interface] = address
print(result)
Команда sh ip int br відображає вивід стовпцями. Всі потрібні поля знаходяться в одному рядку. Скрипт обробляє вивід рядок за рядком і кожен рядок розбиває методом split.
Отриманий список містить стовпці виводу. Так як з усього виводу потрібні тільки інтерфейси, на яких налаштована IP-адреса, виконується перевірка першого символу другого стовпця: якщо перший символ число, значить на інтерфейсі призначена адреса і цей рядок треба обробляти.
Оскільки для кожного рядка є пара ключа та значення, вони присвоюються у
словник: result[interface] = address
.
Результатом виконання скрипта буде такий словник (тут він розбитий на пари ключ-значення для зручності, у реальному виводу скрипта словник відображатиметься в один рядок):
{'FastEthernet0/0': '15.0.15.1',
'FastEthernet0/1': '10.0.12.1',
'FastEthernet0/2': '10.0.13.1',
'Loopback0': '10.1.1.1',
'Loopback100': '100.0.0.1'}
Отримання ключа та значення з різних рядків виводу¶
Дуже часто вивід команд виглядає таким чином, що ключ та значення знаходяться у різних рядках.
Наприклад, з виводу команди sh ip interface треба отримати ім'я інтерфейсу та MTU (файл sh_ip_interface.txt):
Ethernet0/0 is up, line protocol is up
Internet address is 192.168.100.1/24
Broadcast address is 255.255.255.255
Address determined by non-volatile memory
MTU is 1500 bytes
Helper address is not set
...
Ethernet0/1 is up, line protocol is up
Internet address is 192.168.200.1/24
Broadcast address is 255.255.255.255
Address determined by non-volatile memory
MTU is 1500 bytes
Helper address is not set
...
Ethernet0/2 is up, line protocol is up
Internet address is 19.1.1.1/24
Broadcast address is 255.255.255.255
Address determined by non-volatile memory
MTU is 1500 bytes
Helper address is not set
...
Ім'я інтерфейсу знаходиться у рядку Ethernet0/0 is up, line protocol is up
,
а MTU у рядку MTU is 1500 bytes
.
Наприклад, спробуємо запам'ятовувати щоразу інтерфейс у змінну interface і виводити його значення print, але тільки коли зустрічається рядок зі значенням MTU:
with open('sh_ip_interface.txt') as f:
for line in f:
if 'line protocol' in line:
interface = line.split()[0]
elif 'MTU is' in line:
mtu = line.split()[-2]
print('{:15}{}'.format(interface, mtu))
Вивід
Вивід організований таким чином, що спочатку йде рядок з інтерфейсом, а потім через кілька рядків - рядок з MTU. Якщо запам'ятовувати ім'я інтерфейсу кожного разу, коли воно зустрічається, то на момент, коли зустрінеться рядок з MTU, останній записаний інтерфейс - це той, до якого належить MTU.
Тепер, якщо необхідно створити словник з відповідністю інтерфейсу - MTU, достатньо записати значення на момент, коли був знайдений MTU.
result = {}
with open('sh_ip_interface.txt') as f:
for line in f:
if 'line protocol' in line:
interface = line.split()[0]
elif 'MTU is' in line:
mtu = line.split()[-2]
result[interface] = mtu
print(result)
Результатом виконання скрипта буде такий словник (тут він розбитий на пари ключ-значення для зручності, у реальному результаті скрипта словник відображатиметься в один рядок):
{'Ethernet0/0': '1500',
'Ethernet0/1': '1500',
'Ethernet0/2': '1500',
'Ethernet0/3': '1500',
'Loopback0': '1514'}
Цей трюк часто буде корисним, оскільки часто вивід команд організований подібним чином.
Вкладений словник¶
Якщо потрібно отримати кілька параметрів з виводу команди, дуже зручно використовувати словник із вкладеним словником.
Наприклад, з виводу sh ip interface
потрібно отримати два параметри
IP-адресу та MTU:
Ethernet0/0 is up, line protocol is up
Internet address is 192.168.100.1/24
Broadcast address is 255.255.255.255
Address determined by non-volatile memory
MTU is 1500 bytes
Helper address is not set
...
Ethernet0/1 is up, line protocol is up
Internet address is 192.168.200.1/24
Broadcast address is 255.255.255.255
Address determined by non-volatile memory
MTU is 1500 bytes
Helper address is not set
...
Ethernet0/2 is up, line protocol is up
Internet address is 19.1.1.1/24
Broadcast address is 255.255.255.255
Address determined by non-volatile memory
MTU is 1500 bytes
Helper address is not set
...
На першому етапі кожне значення зберігається в змінній, а потім виводяться всі три значення. Значення відображаються, коли зустрічається рядок MTU, оскільки він зустрічається у виводі останнім:
with open('sh_ip_interface.txt') as f:
for line in f:
if 'line protocol' in line:
interface = line.split()[0]
elif 'Internet address' in line:
ip_address = line.split()[-1]
elif 'MTU' in line:
mtu = line.split()[-2]
print('{:15}{:17}{}'.format(interface, ip_address, mtu))
Ethernet0/0 192.168.100.1/24 1500
Ethernet0/1 192.168.200.1/24 1500
Ethernet0/2 19.1.1.1/24 1500
Ethernet0/3 192.168.230.1/24 1500
Loopback0 4.4.4.4/32 1514
Тут ми використовуємо ту саму техніку, що й у попередньому прикладі, але додаємо ще одне вкладення словника:
from pprint import pprint
result = {}
with open('sh_ip_interface.txt') as f:
for line in f:
if 'line protocol' in line:
interface = line.split()[0]
result[interface] = {}
elif 'Internet address' in line:
ip_address = line.split()[-1]
result[interface]['ip'] = ip_address
elif 'MTU' in line:
mtu = line.split()[-2]
result[interface]['mtu'] = mtu
pprint(result)
Щоразу, коли зустрічається інтерфейс, у словнику результатів створюється ключ із назвою інтерфейсу і значення порожній словник. Це потрібно для того, щоб у момент виявлення IP-адреси або MTU, параметр можна було записати до вкладеного словника відповідного інтерфейсу.
Результатом виконання скрипта буде наступний словник:
{'Ethernet0/0': {'ip': '192.168.100.1/24', 'mtu': '1500'},
'Ethernet0/1': {'ip': '192.168.200.1/24', 'mtu': '1500'},
'Ethernet0/2': {'ip': '19.1.1.1/24', 'mtu': '1500'},
'Ethernet0/3': {'ip': '192.168.230.1/24', 'mtu': '1500'},
'Loopback0': {'ip': '4.4.4.4/32', 'mtu': '1514'}}
Вивід із порожніми значеннями¶
Іноді, у виводі команди траплятимуться секції з порожніми значеннями. Наприклад, у
випадку з sh ip interface
можуть траплятися інтерфейси, які виглядають
так:
Ethernet0/1 is up, line protocol is up
Internet protocol processing disabled
Ethernet0/2 is administratively down, line protocol is down
Internet protocol processing disabled
Ethernet0/3 is administratively down, line protocol is down
Internet protocol processing disabled
Відповідно, тут немає MTU та IP-адреси.
І якщо виконати попередній скрипт для файлу з такими інтерфейсами, результат буде таким (вивід для файлу sh_ip_interface2.txt):
{'Ethernet0/0': {'ip': '192.168.100.2/24', 'mtu': '1500'},
'Ethernet0/1': {},
'Ethernet0/2': {},
'Ethernet0/3': {},
'Loopback0': {'ip': '2.2.2.2/32', 'mtu': '1514'}}
Якщо необхідно додавати інтерфейси до словника лише, коли на інтерфейсі призначено IP-адресу, треба перенести створення ключа з ім'ям інтерфейсу на момент, коли зустрічається рядок з IP-адресою:
result = {}
with open('sh_ip_interface2.txt') as f:
for line in f:
if 'line protocol' in line:
interface = line.split()[0]
elif 'Internet address' in line:
ip_address = line.split()[-1]
result[interface] = {}
result[interface]['ip'] = ip_address
elif 'MTU' in line:
mtu = line.split()[-2]
result[interface]['mtu'] = mtu
print(result)
У цьому випадку результатом буде такий словник: