редактирование текстового файла с помощью Python
Мне нужно обновить текстовый файл всякий раз, когда меняется мой IP-адрес, а затем запустить несколько команд из оболочки.
создать переменную последнего известные = "212.171.135.53" Это ip-адрес, который мы имеем при написании этого сценария.
получить текущий IP-адрес. Он будет меняться ежедневно.
создать переменный ток для нового IP.
сравнить (как строки) текущий Последнего известные
Если они одинаковы, exit ()
-
Если они отличаются,
A. "скопируйте" старый файл конфигурации (/etc / ipf.conf), содержащий последний известный IP-адрес в /tmp B. замените LASTKNOWN на CURRENT в /tmp / ipf.файл conf.
C. использование подпроцесса " mv/tmp / ipf.conf/etc / ipf.conf"
Д. Используя подпроцесса выполнение, "МГЛ -ФА -Ф /и т. д./МГЛ.conf"
E. использование подпроцесса execute, " ipnat-CF-f /etc/ipnat.conf" exit ()
Я знаю, как сделать шаги с 1 по 6. Я падаю на часть "редактирование файла", A -> C. Я не могу сказать, какой модуль использовать или должен ли я редактировать файл на месте. Есть так много способов сделать это, я не могу выбрать лучший подход. Думаю, я хочу самый консервативный.
Я знаю, как использовать подпроцесс, поэтому вам не нужно комментировать.
Я не хочу заменять целые строки; просто конкретный пунктирный квадроцикл.
спасибо!
6 ответов
модуль fileinput имеет очень уродливый API, я нахожу красивый модуль для этой задачи -in_place, пример для Python 3:
import in_place
with in_place.InPlace('data.txt') as file:
for line in file:
line = line.replace('test', 'testZ')
file.write(line)
основное отличие от fileinput:
- вместо угона sys.stdout, для записи возвращается новая файловая ручка.
- filehandle поддерживает все стандартные методы ввода-вывода, а не только readline().
например-fileinput может только по строкам редактировать, in_pace позволяет читать весь файл к памяти (если она не большая) и модифицировать ее.
другой способ просто редактировать файлы на месте-использовать fileinput
модуль:
import fileinput, sys
for line in fileinput.input(["test.txt"], inplace=True):
line = line.replace("car", "truck")
# sys.stdout is redirected to the file
sys.stdout.write(line)
заменить LASTKNOWN на CURRENT в /etc / ipf.conf
заменить все сразу
filename = "/etc/ipf.conf"
text = open(filename).read()
open(filename, "w").write(text.replace(LASTKNOWN, CURRENT))
заменить строку за строкой
from __future__ import with_statement
from contextlib import nested
in_filename, outfilename = "/etc/ipf.conf", "/tmp/ipf.conf"
with nested(open(in_filename), open(outfilename, "w")) as in_, out:
for line in in_:
out.write(line.replace(LASTKNOWN, CURRENT))
os.rename(outfilename, in_filename)
Примечание: "/ tmp / ipf.conf " следует заменить на tempfile.NamedTemporaryFile()
или подобное
Примечание: код не проверял.
вы пытаетесь "атомарно" обновить содержимое файла, и на эту тему было много восхитительных войн пламени. Но общая картина такова:--1-->
1) Запишите новый файл во временный файл и убедитесь, что вы сбросили и закрыли.
2) Используйте средства вашей операционной системы для атомарного переименования временного файла в старый файл.
теперь вы просто не можете атомарно переименовать файл в Windows, но похоже, что вы все равно находитесь в unix-подобной системе. Вы атомарно переименовать с помощью os.переименовать().
вероятно, самым простым способом было бы открыть файл с помощью f=open (filename, mode). Затем прочитайте все строки, используя f.readlines () (это вернет список строк, представляющих строки программы).
затем вы можете найти эти строки, чтобы найти адрес и заменить его новым (используя стандартную замену строк, регулярные выражения или все, что вы хотите).
в конце вы можете записать строки обратно в файл, используя f.writelines (строки), которые удобно возвращает список строк.
Примечание: это не эффективный способ сделать это, это просто самый простой. Пожалуйста!--2-->
пример кода:
f = open(filename, "r")
lines = f.readlines()
# Assume that change_ip is a function that takes a string and returns a new one with the ip changed): example below
ret_lines = [change_ip(lines) for line in lines]
new_file = open(new_filename, "w")
new_file.writelines(lines)
def change_ip(str):
''' Gets a string, returns a new string where the ip is changed '''
# Add implementation, something like: return str.replace(old_ip, new_ip) or something similair.
после проверки комментариев и бит кода, который вы положили на pastebin, вот рабочее решение. Начнем с файла / tmp / iiiipf.conf содержит:
Simply a test file 175.48.204.168
And two times 175.48.204.168 on this line 175.48.204.168
Done.
после запуска кода, файл / tmp / iiiipf.conf содержит:
Simply a test file 10.73.144.112
And two times 10.73.144.112 on this line 10.73.144.112
Done.
и вот проверенный рабочий код с моим материалом, объединенным в ваш код pastebin:
import socket
import fileinput
import subprocess
import string
import re
CURRENT = socket.getaddrinfo(socket.gethostname(), None)[0][4][0]
LASTKNOWN = '175.48.204.168'
if CURRENT == LASTKNOWN:
print 'Nevermind.'
subprocess.sys.exit()
else:
cf = open("/tmp/iiiipf.conf", "r")
lns = cf.readlines()
# close it so that we can open for writing later
cf.close()
# assumes LASTKNOWN and CURRENT are strings with dotted notation IP addresses
lns = "".join(lns)
lns = re.sub(LASTKNOWN, CURRENT, lns) # This replaces all occurences of LASTKNOWN with CURRENT
cf = open("/tmp/iiiipf.conf", "w")
cf.write(lns)
cf.close()
этот код будет делать то, что вам нужно, даже если IP-адрес используется несколько раз в конфигурации файл. Он также изменит его в строках комментариев.
этот метод не требует копирования в /tmp и использует один вызов подпроцесса при перезапуске брандмауэра и NAT.