Das geht so:
with open("/etc/apt/sources.list", "r") as sources:
lines = sources.readlines()
with open("/etc/apt/sources.list", "w") as sources:
for line in lines:
sources.write(re.sub(r'^# deb', 'deb', line))
Die with-Anweisung stellt sicher, dass die Datei korrekt geschlossen wird, und das erneute Öffnen der Datei in "w"
Der Modus leert die Datei, bevor Sie darauf schreiben. re.sub(pattern, replace, string) ist das Äquivalent von s/pattern/replace/ in sed/perl.
Bearbeiten: feste Syntax im Beispiel
Erstellen eines selbst erstellten sed
Ersetzung in reinem Python durch no externe Befehle oder zusätzliche Abhängigkeiten ist eine edle Aufgabe, die mit edlen Landminen beladen ist. Wer hätte das gedacht?
Trotzdem ist es machbar. Es ist auch wünschenswert. Wir alle kennen das schon, Leute:„Ich muss ein paar Klartext-Dateien zerkauen, aber ich habe nur Python, zwei Plastikschnürsenkel und eine verschimmelte Dose Maraschino-Kirschen in Bunkerqualität. Hilfe.“
In dieser Antwort bieten wir eine Best-of-Breed-Lösung, die die Großartigkeit früherer Antworten ohne all das unangenehme nicht zusammenfügt -Großartigkeit. Wie Plundra anmerkt, schreibt die ansonsten erstklassige Antwort von David Miller die gewünschte Datei nicht atomar und lädt daher Race Conditions ein (z. B. von anderen Threads und/oder Prozessen, die versuchen, diese Datei gleichzeitig zu lesen). Das ist schlecht. Plundras ansonsten ausgezeichnete Antwort löst das Problem, während noch mehr eingeführt werden – darunter zahlreiche schwerwiegende Codierungsfehler, eine kritische Sicherheitslücke (die Berechtigungen und andere Metadaten der Originaldatei nicht beibehalten) und eine vorzeitige Optimierung, die reguläre Ausdrücke durch Zeichenindizierung auf niedriger Ebene ersetzt. Das ist auch schlecht.
Großartig, vereinigt euch!
import re, shutil, tempfile
def sed_inplace(filename, pattern, repl):
'''
Perform the pure-Python equivalent of in-place `sed` substitution: e.g.,
`sed -i -e 's/'${pattern}'/'${repl}' "${filename}"`.
'''
# For efficiency, precompile the passed regular expression.
pattern_compiled = re.compile(pattern)
# For portability, NamedTemporaryFile() defaults to mode "w+b" (i.e., binary
# writing with updating). This is usually a good thing. In this case,
# however, binary writing imposes non-trivial encoding constraints trivially
# resolved by switching to text writing. Let's do that.
with tempfile.NamedTemporaryFile(mode='w', delete=False) as tmp_file:
with open(filename) as src_file:
for line in src_file:
tmp_file.write(pattern_compiled.sub(repl, line))
# Overwrite the original file with the munged temporary file in a
# manner preserving file attributes (e.g., permissions).
shutil.copystat(filename, tmp_file.name)
shutil.move(tmp_file.name, filename)
# Do it for Johnny.
sed_inplace('/etc/apt/sources.list', r'^\# deb', 'deb')
massedit.py (http://github.com/elmotec/massedit) erledigt das Gerüst für Sie und lässt nur die Regex zu schreiben. Es befindet sich noch in der Beta-Phase, aber wir suchen nach Feedback.
python -m massedit -e "re.sub(r'^# deb', 'deb', line)" /etc/apt/sources.list
zeigt die Unterschiede (vorher/nachher) im Diff-Format.
Fügen Sie die Option -w hinzu, um die Änderungen in die Originaldatei zu schreiben:
python -m massedit -e "re.sub(r'^# deb', 'deb', line)" -w /etc/apt/sources.list
Alternativ können Sie jetzt die API verwenden:
>>> import massedit
>>> filenames = ['/etc/apt/sources.list']
>>> massedit.edit_files(filenames, ["re.sub(r'^# deb', 'deb', line)"], dry_run=True)
Dies ist ein so anderer Ansatz, dass ich meine andere Antwort nicht bearbeiten möchte. Verschachtelter with
da ich 3.1 nicht verwende (wobei with A() as a, B() as b:
funktioniert).
Könnte ein bisschen übertrieben sein, die sources.list zu ändern, aber ich möchte sie für zukünftige Suchen veröffentlichen.
#!/usr/bin/env python
from shutil import move
from tempfile import NamedTemporaryFile
with NamedTemporaryFile(delete=False) as tmp_sources:
with open("sources.list") as sources_file:
for line in sources_file:
if line.startswith("# deb"):
tmp_sources.write(line[2:])
else:
tmp_sources.write(line)
move(tmp_sources.name, sources_file.name)
Dies sollte sicherstellen, dass andere Personen, die die Datei lesen, keine Race-Conditions haben. Oh, und ich bevorzuge str.startswith(...), wenn Sie auf einen regulären Ausdruck verzichten können.