Search and replace a line in a file in Python
The shortest way would probably be to use the fileinput module. For example, the following adds line numbers to a file, in-place:
import fileinputfor line in fileinput.input("test.txt", inplace=True): print('{} {}'.format(fileinput.filelineno(), line), end='') # for Python 3 # print "%d: %s" % (fileinput.filelineno(), line), # for Python 2
What happens here is:
- The original file is moved to a backup file
- The standard output is redirected to the original file within the loop
- Thus any
print
statements write back into the original file
fileinput
has more bells and whistles. For example, it can be used to automatically operate on all files in sys.args[1:]
, without your having to iterate over them explicitly. Starting with Python 3.2 it also provides a convenient context manager for use in a with
statement.
While fileinput
is great for throwaway scripts, I would be wary of using it in real code because admittedly it's not very readable or familiar. In real (production) code it's worthwhile to spend just a few more lines of code to make the process explicit and thus make the code readable.
There are two options:
- The file is not overly large, and you can just read it wholly to memory. Then close the file, reopen it in writing mode and write the modified contents back.
- The file is too large to be stored in memory; you can move it over to a temporary file and open that, reading it line by line, writing back into the original file. Note that this requires twice the storage.
I guess something like this should do it. It basically writes the content to a new file and replaces the old file with the new file:
from tempfile import mkstempfrom shutil import move, copymodefrom os import fdopen, removedef replace(file_path, pattern, subst): #Create temp file fh, abs_path = mkstemp() with fdopen(fh,'w') as new_file: with open(file_path) as old_file: for line in old_file: new_file.write(line.replace(pattern, subst)) #Copy the file permissions from the old file to the new file copymode(file_path, abs_path) #Remove original file remove(file_path) #Move new file move(abs_path, file_path)
Here's another example that was tested, and will match search & replace patterns:
import fileinputimport sysdef replaceAll(file,searchExp,replaceExp): for line in fileinput.input(file, inplace=1): if searchExp in line: line = line.replace(searchExp,replaceExp) sys.stdout.write(line)
Example use:
replaceAll("/fooBar.txt","Hello\sWorld!$","Goodbye\sWorld.")