Вы создаете регулярное выражение, передавая строку конструктору RegExp.
Вам нужно избежать \
, чтобы ваш строковый литерал мог выразить его как данные, прежде чем преобразовать его в обычный выражение.
re.sub()
принимает 3 параметра, но здесь проблема не в этом. Фактически вы не замените текст, который пытаетесь заменить, простой записью в файл, не пытаясь сначала найти смещение, в которое вы хотите записать, с помощью функции seek()
. Это проблема для вас, потому что ваша замещающая строка длиннее, чем оригинал, и вы, вероятно, в конечном итоге будете записывать данные, которые вы не собирались. Другая проблема заключается в том, что вы решили открыть файл для добавления, которое в некоторых системах добавляется ТОЛЬКО в конец файла, что, я уверен, не является вашим намерением.
Все, что вам действительно нужно сделать, это открыть файл и скопировать данные в переменную. Затем попытайтесь найти строку и заменить ее. Наконец, запишите все это обратно в файл.
def write_over():
file_name = '/etc/sysctl.conf'
new_string = 'net.ipv4.ipfrag_low_thresh = 15728640'
fh = open(file_name, 'r+')
data = fh.read()
result = re.search(r'net\.ipv4\.ipfrag_low_thresh\s?=?\s?[0-9]*', data) # check this regex, it may not be exactly what you need
if result:
if result.group(0) == new_string: # if the string is exact match, do nothing
fh.close()
return
data = data.replace(result.group(0), new_string + '\n') # else replace with new string
fh.truncate(0) # this will clear the contents of the file
fh.seek(0)
fh.write(data) # write the new data in its entirety to the file
fh.close()
else:
fh.write('\n' + new_string) # if the line was not in the file at all
fh.close()
Вот другой подход, использующий типы данных Python вместо простого строкового регулярного выражения (слишком легко испортить регулярное выражение и разрушить структуру файла).
Работа с поддельным примером файла:
# hash comment
; colon comment
one = 1
net.ipv4.ipfrag_low_thresh = 1234
another = ok
код:
#!/usr/bin/env python
setting_map = {
'net.ipv4.ipfrag_low_thresh': 15728640,
'net.ipv4.ipfrag_high_thresh': 16777216,
}
found = {setting: False for setting in setting_map}
to_write = []
def good_setting(setting):
return '{} = {}'.format(setting, setting_map[setting])
with open('sysctl.conf') as f:
for line in f:
line = line.rstrip() # remove newlines
try:
setting = line.split('=')[0].strip() # remove spaces if present
value = int(line.split('=')[-1].strip())
except Exception as e:
# you probably don't want to print, but i put it here for demonstration
print('could not parse line "{}"; exception: {}'.format(line, repr(e)))
# keep it as-is
to_write.append(line)
continue
if setting in setting_map:
found[setting] = True
if value != setting_map[setting]:
print('FOUND "{}" with value "{}"; overwriting with "{}"'.format(
setting, value, setting_map[setting]
))
to_write.append(good_setting(setting))
continue
to_write.append(line)
# opening as 'w' will wipe the file, but we're re-writing every line
# or you can write to a different file if you'd like
with open('sysctl.conf', 'w') as f:
f.write('\n'.join(to_write))
f.write('\n')
for setting in setting_map:
if not found[setting]:
print('ADDING "{}"'.format(good_setting(setting)))
f.write('{}\n'.format(good_setting(setting)))
вывод:
could not parse line "# hash comment"; exception: ValueError("invalid literal for int() with base 10: '# hash comment'")
could not parse line " ; colon comment"; exception: ValueError("invalid literal for int() with base 10: '; colon comment'")
could not parse line ""; exception: ValueError("invalid literal for int() with base 10: ''")
FOUND "net.ipv4.ipfrag_low_thresh" with value "1234"; overwriting with "15728640"
could not parse line "another = ok"; exception: ValueError("invalid literal for int() with base 10: 'ok'")
ADDING "net.ipv4.ipfrag_high_thresh = 16777216"
файл после:
# hash comment
; colon comment
one = 1
net.ipv4.ipfrag_low_thresh = 15728640
another = ok
net.ipv4.ipfrag_high_thresh = 16777216