У сучасному мережевому адмініструванні знання Python стає незамінним інструментом, а вміння працювати з файлами — критично важливим навиком. Збереження конфігурацій, обробка логів, автоматизація обміну даними — усе це неможливо без грамотної взаємодії зі структурованими та неструктурованими файлами. У цій статті ви дізнаєтеся, як ефективно використовувати можливості мови для роботи з файлами у щоденній практиці мережевого спеціаліста. Цей матеріал створено спеціально для тих, хто прагне поєднати гнучкість Python із реальними задачами автоматизації в інфраструктурі.
У практичній роботі, щоб повною мірою застосовувати знання, отримані в попередніх розділах, необхідно добре розумітися на роботі з файлами. Під час взаємодії з мережевим обладнанням, а також у багатьох інших випадках, доводиться мати справу з різними типами файлів. Наприклад, конфігураційні файли можуть бути простими текстовими документами без складної структури. Їх обробка є однією з тем цього розділу. Окремо існують шаблони конфігурацій, для яких зазвичай використовується спеціальний формат і розглядається застосування шаблонізатора Jinja2 для їх створення.
Ще один поширений тип — файли, що містять параметри підключення; вони часто мають структуру у вигляді YAML, JSON або CSV, і методи їх обробки описуються у відповідному розділі про серіалізацію. Існує також необхідність у роботі з іншими скриптами Python, де важливо вміти грамотно взаємодіяти з модулями. У даному розділі головний акцент зроблено на взаємодії з простими текстовими файлами, такими як конфігурації пристроїв Cisco. Основні дії, які детально пояснюються, охоплюють відкриття, читання, запис і закриття файлів. Тут подано лише базову інформацію, необхідну для впевненої роботи з файлами в Python, а для поглибленого вивчення завжди можна звернутися до офіційної документації.
Для початку роботи з файлом його треба відкрити. Для відкриття файлів найчастіше використовується функція open:
file = open('file_name.txt', 'r')
У функції open():
Функція open() у Python дозволяє відкривати файли для подальшої роботи з ними. Першим аргументом передається ім’я або шлях до файлу (це може бути як абсолютний, так і відносний шлях), другим — режим, у якому файл буде відкрито. Наприклад, символ 'r' означає відкриття файлу тільки для читання, і це є режимом за замовчуванням. Якщо потрібно не лише читати, а й змінювати вміст, використовується режим 'r+'.
Для створення або повного перезапису файлу використовується режим 'w'. У цьому випадку, якщо файл вже існує, його вміст повністю стирається, а якщо не існує — створюється новий. Аналогічно діє режим 'w+', але з можливістю читання. Якщо мета — додати нові дані в кінець наявного файлу, не зачіпаючи вже існуючу інформацію, застосовується режим 'a'. Для читання і дописування одночасно використовують 'a+'.
Після відкриття файлу з допомогою open() створюється файловий об’єкт, до якого можна застосовувати методи читання, запису чи закриття в залежності від обраного режиму.
r – read;
a – append;
w – write.
У Python є кілька методів читання файлу:
read– Зчитує вміст файлу в рядок
readline– зчитує файл рядково
readlines– зчитує рядки файлу та створює список із рядків
Подивимося як зчитувати вміст файлів на прикладі файлу r1.txt:
! service timestamps debug datetime msec localtime show-timezone year service timestamps log datetime msec localtime show-timezone year service password-encryption service sequence-numbers ! no ip domain lookup ! ip ssh version 2 !
readМетод read– зчитує весь файл в один рядок.
Приклад використання методу read:
In [1]: f = open('r1.txt')
In [2]: f.read()
Out[2]: '!\nservice timestamps debug datetime msec localtime show-timezone year\nservice timestamps log datetime msec localtime show-timezone year\nservice password-encryption\nservice sequence-numbers\n!\nno ip domain lookup\n!\nip ssh version 2\n!\n'
In [3]: f.read()
Out[3]: ''
При повторному читанні файлу в 3 рядку, відображається порожній рядок. Так відбувається через те, що при викликі методу зчитується readвесь файл.seek.
readlineФайл можна вважати за допомогою методу readline:
In [4]: f = open('r1.txt')
In [5]: f.readline()
Out[5]: '!\n'
In [6]: f.readline()
Out[6]: 'service timestamps debug datetime msec localtime show-timezone year\n'
Але найчастіше простіше пройтися по об’єкту file в циклі, не використовуючи методи read...
In [7]: f = open('r1.txt')
In [8]: for line in f:
...: print(line)
...:
!
service timestamps debug datetime msec localtime show-timezone year
service timestamps log datetime msec localtime show-timezone year
service password-encryption
service sequence-numbers
!
no ip domain lookup
!
ip ssh version 2
!
readlinesЩе один корисний метод – readlines. Він зчитує рядки файлу до списку:
In [9]: f = open('r1.txt')
In [10]: f.readlines()
Out[10]:
['!\n',
'service timestamps debug datetime msec localtime show-timezone year\n',
'service timestamps log datetime msec localtime show-timezone year\n',
'service password-encryption\n',
'service sequence-numbers\n',
'!\n',
'no ip domain lookup\n',
'!\n',
'ip ssh version 2\n',
'!\n']
Якщо потрібно отримати рядки файлу, але без перекладу рядка в кінці, можна скористатися методом splitі як роздільник вказати символ \n:
In [11]: f = open('r1.txt')
In [12]: f.read().split('\n')
Out[12]:
['!',
'service timestamps debug datetime msec localtime show-timezone year',
'service timestamps log datetime msec localtime show-timezone year',
'service password-encryption',
'service sequence-numbers',
'!',
'no ip domain lookup',
'!',
'ip ssh version 2',
'!',
'']
Зауважте, що останній елемент списку – порожній рядок.
Якщо перед виконанням split, скористатися методом rstrip, список буде без порожнього рядка наприкінці:
In [13]: f = open('r1.txt')
In [14]: f.read().rstrip().split('\n')
Out[14]:
['!',
'service timestamps debug datetime msec localtime show-timezone year',
'service timestamps log datetime msec localtime show-timezone year',
'service password-encryption',
'service sequence-numbers',
'!',
'no ip domain lookup',
'!',
'ip ssh version 2',
'!']
seekДосі файл щоразу доводилося відкривати заново, щоб знову його рахувати. Так відбувається через те, що після методів читання курсор знаходиться в кінці файлу. І повторне читання повертає порожній рядок. Щоб ще раз рахувати інформацію з файлу, потрібно скористатися методом seek, який переміщує курсор у потрібне положення.
Приклад відкриття файлу та зчитування вмісту:
In [15]: f = open('r1.txt')
In [16]: print(f.read())
!
service timestamps debug datetime msec localtime show-timezone year
service timestamps log datetime msec localtime show-timezone year
service password-encryption
service sequence-numbers
!
no ip domain lookup
!
ip ssh version 2
!
Якщо ще раз викликати метод read, повертається порожній рядок:
In [17]: print(f.read())
Але за допомогою методу seekможна перейти на початок файлу (0 означає початок файлу):
In [18]: f.seek(0)
Після того як за допомогою seekкурсора було переведено на початок файлу, можна знову зчитувати вміст:
In [19]: print(f.read()) ! service timestamps debug datetime msec localtime show-timezone year service timestamps log datetime msec localtime show-timezone year service password-encryption service sequence-numbers ! no ip domain lookup ! ip ssh version 2 !
При записі дуже важливо визначитися з режимом відкриття файлу, щоб випадково його не видалити:
w– Відкрити файл для запису. Якщо файл існує, його вміст видаляється
a– Відкрити файл для доповнення запису. Дані додаються до кінця файлу
При цьому обидва режими створюють файл, якщо він не існує.
Для запису у файл використовуються такі методи:
write– записати у файл один рядок
writelines– дозволяє передавати як аргумент список рядків
writeМетод writeчекає рядок для запису.
Наприклад, візьмемо список рядків із конфігурацією:
In [1]: cfg_lines = ['!', ...: 'service timestamps debug datetime msec localtime show-timezone year', ...: 'service timestamps log datetime msec localtime show-timezone year', ...: 'service password-encryption', ...: 'service sequence-numbers', ...: '!', ...: 'no ip domain lookup', ...: '!', ...: 'ip ssh version 2', ...: '!']
Відкриття файлу r2.txt в режимі запису:
In [2]: f = open('r2.txt', 'w')
Перетворимо список команд в один великий рядок за допомогою join:
In [3]: cfg_lines_as_string = '\n'.join(cfg_lines) In [4]: cfg_lines_as_string Out[4]: '!\nservice timestamps debug datetime msec localtime show-timezone year\nservice timestamps log datetime msec localtime show-timezone year\nservice password-encryption\nservice sequence-numbers\n!\nno ip domain lookup\n!\nip ssh version 2\n!'
Запис рядка у файл:
In [5]: f.write(cfg_lines_as_string)
Аналогічно можна додати рядок вручну:
In [6]: f.write('\nhostname r2')
Після завершення роботи з файлом його необхідно закрити:
In [7]: f.close()
Оскільки ipython підтримує команду cat, можна легко переглянути вміст файлу:
In [8]: cat r2.txt ! service timestamps debug datetime msec localtime show-timezone year service timestamps log datetime msec localtime show-timezone year service password-encryption service sequence-numbers ! no ip domain lookup ! ip ssh version 2 ! hostname r2
writelinesМетод writelinesчекає на список рядків, як аргумент.
Запис списку рядків cfg_lines у файл:
In [1]: cfg_lines = ['!',
...: 'service timestamps debug datetime msec localtime show-timezone year',
...: 'service timestamps log datetime msec localtime show-timezone year',
...: 'service password-encryption',
...: 'service sequence-numbers',
...: '!',
...: 'no ip domain lookup',
...: '!',
...: 'ip ssh version 2',
...: '!']
In [9]: f = open('r2.txt', 'w')
In [10]: f.writelines(cfg_lines)
In [11]: f.close()
In [12]: cat r2.txt
!service timestamps debug datetime msec localtime show-timezone yearservice timestamps log datetime msec localtime show-timezone yearservice password-encryptionservice sequence-numbers!no ip domain lookup!ip ssh version 2!
В результаті всі рядки зі списку записалися в один рядок файлу, тому що в кінці рядків не було символу \n.
Додати переклад рядка можна по-різному. Наприклад, можна просто обробити список у циклі:
In [13]: cfg_lines2 = [] In [14]: for line in cfg_lines: ....: cfg_lines2.append(line + '\n') ....: In [15]: cfg_lines2 Out[15]: ['!\n', 'service timestamps debug datetime msec localtime show-timezone year\n', 'service timestamps log datetime msec localtime show-timezone year\n', 'service password-encryption\n', 'service sequence-numbers\n', '!\n', 'no ip domain lookup\n', '!\n', 'ip ssh version 2\n',
Якщо записати отриманий список назад у файл, він уже міститиме переклади рядків:
In [18]: f = open('r2.txt', 'w')
In [19]: f.writelines(cfg_lines2)
In [20]: f.close()
In [21]: cat r2.txt
!
service timestamps debug datetime msec localtime show-timezone year
service timestamps log datetime msec localtime show-timezone year
service password-encryption
service sequence-numbers
!
no ip domain lookup
!
ip ssh version 2
!
У реальному житті для закриття файлів найчастіше використовується конструкція with. Її набагато зручніше використовувати, ніж закривати файл явно. Але, оскільки в житті можна зустріти і метод close, у цьому розділі розглядається як його використати.
Після завершення роботи з файлом його потрібно закрити. У деяких випадках Python може самостійно закрити файл. Але краще не розраховувати і закривати файл явно.
closeМетод close зустрічався у розділі запис файлів. Там він був потрібний для того, щоб вміст файлу був записаний на диск.
Для цього в Python є окремий метод flush. Але так як у прикладі із записом файлів, не потрібно було виконувати жодних операцій, файл можна було закрити.
Відкриємо файл r1.txt:
In [1]: f = open('r1.txt', 'r')
Тепер можна вважати вміст:
In [2]: print(f.read()) ! service timestamps debug datetime msec localtime show-timezone year service timestamps log datetime msec localtime show-timezone year service password-encryption service sequence-numbers ! no ip domain lookup ! ip ssh version 2 !
Об’єкт file має спеціальний атрибут closed, який дозволяє перевірити, закритий файл чи ні. Якщо файл відкритий, він повертає False:
In [3]: f.closed Out[3]: False
Тепер закриваємо файл і знову перевіряємо closed:
In [4]: f.close() In [5]: f.closed Out[5]: True
Якщо спробувати прочитати файл, виникне виняток:
In [6]: print(f.read()) ------------------------------------------------------------------ ValueError Traceback (most recent call last) <ipython-input-53-2c962247edc5> in <module>() ----> 1 print(f.read()) ValueError: I/O operation on closed file
Конструкція з називається менеджер контексту. У Python існує більш зручний спосіб роботи з файлами, ніж ті, які використовувалися досі – конструкція with:
In [1]: with open('r1.txt', 'r') as f:
....: for line in f:
....: print(line)
....:
!
service timestamps debug datetime msec localtime show-timezone year
service timestamps log datetime msec localtime show-timezone year
service password-encryption
service sequence-numbers
!
no ip domain lookup
!
ip ssh version 2
!
Крім того, конструкція withгарантує закриття файлу автоматично.
Зверніть увагу на те, як зчитуються рядки файлу:
for line in f:
print(line)
Коли з файлом потрібно працювати рядково, краще використати такий варіант.
У попередньому висновку між рядками файлу були зайві порожні рядки, так як print додає ще один переклад рядка.
Щоб позбавитися цього, можна використовувати метод rstrip:
In [2]: with open('r1.txt', 'r') as f:
....: for line in f:
....: print(line.rstrip())
....:
!
service timestamps debug datetime msec localtime show-timezone year
service timestamps log datetime msec localtime show-timezone year
service password-encryption
service sequence-numbers
!
no ip domain lookup
!
ip ssh version 2
!
In [3]: f.closed
Out[3]: True
І звичайно ж, з конструкцією withможна використовувати не тільки такий рядковий варіант зчитування, всі методи, що розглядалися до цього, також працюють:
In [4]: with open('r1.txt', 'r') as f:
....: print(f.read())
....:
!
service timestamps debug datetime msec localtime show-timezone year
service timestamps log datetime msec localtime show-timezone year
service password-encryption
service sequence-numbers
!
no ip domain lookup
!
ip ssh version 2
!
Іноді потрібно працювати одночасно із двома файлами. Наприклад, треба записати деякі рядки з одного файлу, до іншого.
У такому випадку, у блоці with можна відкривати два файли таким чином:
In [5]: with open('r1.txt') as src, open('result.txt', 'w') as dest:
...: for line in src:
...: if line.startswith('service'):
...: dest.write(line)
...:
In [6]: cat result.txt
service timestamps debug datetime msec localtime show-timezone year
service timestamps log datetime msec localtime show-timezone year
service password-encryption
service sequence-numbers
Це рівнозначно таким двом блокам with:
In [7]: with open('r1.txt') as src:
...: with open('result.txt', 'w') as dest:
...: for line in src:
...: if line.startswith('service'):
...: dest.write(line)
...:
У цьому підрозділі розглядається робота з файлами та поєднуються теми: файли, цикли та умови.
При обробці виведення команд чи конфігурації часто потрібно буде записати підсумкові дані у словник. Не завжди очевидно, як обробляти виведення команд і як загалом підходити до розбору виведення на частини. У цьому підрозділі розглядаються кілька прикладів, із зростаючим рівнем складності.
У цьому прикладі розбиратиметься висновок команди 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'}
Дуже часто виведення команд виглядає таким чином, що ключ та значення знаходяться у різних рядках. І треба придумати, яким чином обробляти висновок, щоб отримати потрібну відповідність.
Наприклад, з виведення команди треба отримати відповідність ім’я інтерфейсу – MTU (файл sh_ip_interface.txt):sh ip interface:
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 у рядку виду .Ethernet0/0 is up, line protocol is upMTU is 1500 bytes
Наприклад, спробуємо запам’ятовувати щоразу інтерфейс та виводити його значення, коли зустрічається MTU, разом із значенням MTU:
In [2]: 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))
...:
Ethernet0/0 1500
Ethernet0/1 1500
Ethernet0/2 1500
Ethernet0/3 1500
Loopback0 1514
Висновок організований таким чином, що спочатку йде рядок з інтерфейсом, а потім через кілька рядків – рядок з MTU. Якщо запам’ятовувати ім’я інтерфейсу кожного разу, коли воно зустрічається, то на момент, коли зустрінеться рядок з MTU, останній запам’ятований інтерфейс – це той, до якого належить MTU.
Тепер, якщо необхідно створити словник з відповідністю інтерфейсу – MTU, достатньо записати значення на момент, коли був знайдений MTU.
Файл working_with_dict_example_2.py:
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, тому що він йде останнім:
In [2]: 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
Тут використовується такий самий прийом, як у попередньому прикладі, але додається ще одна вкладеність словника:
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
print(result)
Щоразу, коли зустрічається інтерфейс, у словнику ‘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-адресою (файл working_with_dict_example_4.py):
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)
У цьому випадку результатом буде такий словник:
{'Ethernet0/0': {'ip': '192.168.100.2/24', 'mtu': '1500'},
'Loopback0': {'ip': '2.2.2.2/32', 'mtu': '1514'}}
Розділ дає базові, але фундаментальні знання для впевненої роботи з текстовими файлами в Python. Через практичні приклади пояснюється, як зчитувати, записувати й обробляти конфігураційні дані з реальних мережевих сценаріїв, що є необхідним для ефективної автоматизації та аналізу мереж.