edit text file using Python

大兔子大兔子 提交于 2019-11-28 20:56:53

fileinput module has very ugly API, I find beautiful module for this task - in_place, example for 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)

main difference from fileinput:

  • Instead of hijacking sys.stdout, a new filehandle is returned for writing.
  • The filehandle supports all of the standard I/O methods, not just readline().

for example - fileinput can line by line editing only, in_pace allow read whole file to memory (if it not big) and modify it.

Tim Jones

Another way to simply edit files in place is to use the fileinput module:

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)

Replace LASTKNOWN by CURRENT in /etc/ipf.conf

Replace all at once

filename = "/etc/ipf.conf"
text = open(filename).read()
open(filename, "w").write(text.replace(LASTKNOWN, CURRENT))

Replace line by line

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)

Note: "/tmp/ipf.conf" should be replaced by tempfile.NamedTemporaryFile() or similar
Note: the code is not tested.

You're trying to "atomically" update the contents of a file, and there have been many delightful flame wars on the subject. But the general pattern is:

1) Write the new file to a temp file, and make sure you flush and close.

2) Use your operating system's facilities to atomically rename the temp file to the old file.

Now, you simply can't atomically rename a file in Windows, but it sounds like you're on a unix-like system anyway. You atomically rename using os.rename().

Probably the simplest way would be to open a file using f=open(filename, mode). Then, read all the lines using f.readlines() (this will return a list of strings representing the lines of the program).

You can then search these strings to find the address and replace it with the new one (using standard string replacing, regular expressions, or whatever you want).

At the end, you can write the lines back to the file using f.writelines(lines), which conveniently takes back a list of lines.

NOTE: This is not an efficient way to do this, it's just the easiest. Please

Example code:

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.

After checking the comments and the bit of code that you put on pastebin, here is a working solution. To begin with, the file /tmp/iiiipf.conf contains:

Simply a test file 175.48.204.168

And two times 175.48.204.168 on this line 175.48.204.168

Done.

After running the code, the file /tmp/iiiipf.conf contains:

Simply a test file 10.73.144.112

And two times 10.73.144.112 on this line 10.73.144.112

Done.

And here is the tested working code with my stuff merged into your pastebin code:

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()

This bit of code will do what you need even if the IP address is used several times within the configuration file. It will also change it in comment lines.

This method does not require copying to /tmp and uses one less subprocess call when restarting the firewall and NAT.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!