使用Python编辑文本文件

时间:2009-10-17 17:35:22

标签: python text editing

我需要在IP地址发生变化时更新文本文件,然后再从shell运行一些命令。

  1. 创建变量LASTKNOWN =“212.171.135.53” 这是我们编写此脚本时的IP地址。

  2. 获取当前的IP地址。它会每天更改。

  3. 为新IP创建变量CURRENT。

  4. 比较(作为字符串)CURRENT到LASTKNOWN

  5. 如果它们相同,请退出()

  6. 如果不同,

    一个。将包含LASTKNOWN IP地址的旧配置文件(/etc/ipf.conf)“复制”到/ tmp B.用/tmp/ipf.conf文件中的CURRENT替换LASTKNOWN C.使用子进程“mv /tmp/ipf.conf /etc/ipf.conf”
    D.使用子进程执行“ipf -Fa -f /etc/ipf.conf”
    E.使用子进程执行,“ipnat -CF -f /etc/ipnat.conf”

  7. 出口()

  8. 我知道如何执行第1步到第6步。我堕落在“文件编辑”部分,A - > C.我无法分辨使用什么模块或是否应该编辑文件。有很多方法可以做到这一点,我无法决定最好的方法。我想我想要最保守的一个。

    我知道如何使用子进程,因此您无需对此进行评论。

    我不想替换整条线;只是一个特定的点缀四边形

    谢谢!

6 个答案:

答案 0 :(得分:27)

简单编辑文件的另一种方法是使用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)

答案 1 :(得分:6)

在/etc/ipf.conf

中用CURRENT替换LASTKNOWN

立即替换所有

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()或类似的替换 注意:代码未经过测试。

答案 2 :(得分:2)

你试图“原子地”更新文件的内容,并且在这个主题上有许多令人愉快的火焰战争。但一般模式是:

1)将新文件写入临时文件,并确保刷新并关闭。

2)使用操作系统的工具将临时文件原子重命名为旧文件。

现在,您根本无法在Windows中自动重命名文件,但听起来您仍然使用类似unix的系统。您使用os.rename()原子重命名。

答案 3 :(得分:2)

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,而是返回一个新的文件句柄进行写作。
  • 文件句柄支持所有标准I / O方法,而不仅仅是readline()。

例如 - fileinput只能逐行编辑,in_pace允许将整个文件读取到内存(如果不大)并修改它。

答案 4 :(得分:1)

最简单的方法可能是使用f = open(文件名,模式)打开文件。然后,使用f.readlines()读取所有行(这将返回表示程序行的字符串列表)。

然后,您可以搜索这些字符串以查找地址并将其替换为新地址(使用标准字符串替换,正则表达式或任何您想要的地址)。

最后,您可以使用f.writelines(lines)将行写回文件,这样可以方便地回收行列表。

注意:这不是一种有效的方法,它只是最简单的方法。请

示例代码:

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.

答案 5 :(得分:0)

在检查了你在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时使用少一个子进程调用。