我想从文件中删除某些特定行。假设它是第 20-37 行,然后是第 45 行。如果不指定这些行的内容,我该怎么做?
答案1
与sed
,像这样:
sed '20,37d; 45d' < input.txt > output.txt
如果您想就地执行此操作:
sed --in-place '20,37d; 45d' file.txt
答案2
如果该文件适合内存,您也可以使用ed
.
这些命令与上面的命令非常相似,sed
其中一个显着差异:您必须按降序传递要删除的行号/范围列表(从最高的行号/范围到最低的行号/范围)。原因是,当您使用 删除/插入/拆分/连接行时ed
,文本缓冲区会在每个子命令之后更新,因此如果您删除某些行,则以下行的其余部分将不再位于缓冲区中的同一位置。执行下一个子命令。所以你必须从头开始1。
到位编辑:
ed -s in_file <<IN
45d
20,37d
w
q
IN
或者
ed -s in_file <<< $'45d\n20,37d\nw\nq\n'
或者
printf '%s\n' 45d 20,37d w q | ed -s in_file
如果您想打印结果输出而不是写入文件,请将w
rite替换为 rint。,p
如果您想保持原始文件完整并写入另一个文件,您可以将新文件名传递给w
rite 子命令:
ed -s in_file <<IN
78,86d
65d
51d
20,37d
w out_file
q
IN
1
除非您愿意在每次d
elete 之后计算新的行号,这对于这种特殊情况来说非常简单(删除第 20-37 行,即 18 行后,第 45 行变为第 27 行),因此您可以运行:
ed -s in_file <<IN
20,37d
27d
w
q
IN
但是,如果您必须删除多个行号/范围,则向后操作是理所当然的。
答案3
只需将其读入内存,更改它,然后写回即可。你可以做类似的事情
filename = "foo"
f = open(filename, 'r+')
linenums = [1, 3]
s = [y for x, y in enumerate(f) if x not in [line-1 for line in linenums]]
f.seek(0)
f.write(''.join(s))
f.truncate(f.tell())
f.close()
使用 5 行文件进行测试。致谢http://pleac.sourceforge.net/pleac_python/fileaccess.html,请参阅“在没有临时文件的情况下就地修改文件”部分。也可以看看https://stackoverflow.com/questions/125703/how-do-i-modify-a-text-file-in-python
一些注意事项:
可以先截断文件,然后写入文件,而不是如上所述先写入,然后截断。但是,我不知道有哪个 Python 标志允许读取,然后进行截断写入。但也许我遗漏了一些东西,因为该文件并不那么清楚。这让我想到
有时 Python 文档真的很糟糕。看 http://docs.python.org/library/functions.html#open
模式“r+”、“w+”和“a+”打开文件进行更新(请注意,“w+”会截断文件)。
这对你来说意味着什么吗? “开放更新”到底是什么?
我不知道在 python 中执行此操作是否比在 unixy 中(例如流编辑器)更好。它可能更便携,但我不知道 sed 的便携性如何。我只是这样写,因为我对低级编程比使用经典的 unix 工具更舒服,如果它们完全按照你的要求做,那就很好,但(我认为)通常不太灵活。
这种方法(操作内存中的文件)用内存换取磁盘空间。它应该可以在具有几 Gb 内存的机器上运行,对于高达几百 Mb 的文件。 Python 不能非常有效地处理字符串,因此切换到 C/C++ 会稍微提高性能并大大减少内存使用量。
答案4
您可以在 Ex 模式下使用 Vim:
ex -sc '20,37d|45d|x' file
d
删除x
保存并关闭