在文件中查找一行并删除该行

15
$ cat example.txt

产量:

example
test
example

我想从这个文件中删除“test”字符串。

$ grep -v test example.txt > example.txt 
$ cat example.txt 
$

以下代码可行,但我有一种感觉还有更好的方式!

$ grep -v test example.txt > example.txt.tmp;mv example.txt.tmp example.txt 
$ cat example.txt 
example
example
值得注意的是,这将在一份超过10,000行的文件中进行。祝好。

这里真正的问题是:“为什么 grep -v test example.txt > example.txt 会使文件 example.txt 变为空?难道不是 > 用于删除文件内容并添加新内容,而 >> 用于追加内容吗?那么为什么 > 删除内容而不添加新内容呢? - 71GA
2
由于bash命令处理的方式,">"符号会先打开(并清空)文件,然后grep从中读取。但是它不会读取任何内容,因为由于">"符号,该文件已经被清空为空。 - Jesse_Pinkman
也许你可以尝试使用带有-v选项的正则表达式,它可能会起作用。 - dedshit
3个回答

22

你可以使用sed,

sed -i '/test/d' example.txt

-i选项将更改保存到文件中,因此您无需使用重定向运算符。

-i[SUFFIX], --in-place[=SUFFIX]
             edit files in place (makes backup if SUFFIX supplied)

如果我正在寻找 t/e/s/t,会怎样? - bsmoo
sed -i '/t\/e\/s\/t/d' example.txt - Avinash Raj
或者使用不同的分隔符。 - Fernando Basso
无论你选择哪个分隔符 X,都会有同样的问题/疑问:如果我要查找的是tXeXsXt,怎么办? - Ed Morton

17
你做得是正确的,但在 mv 前使用 && 以确保 grep 成功,否则会删除你的原始文件:
grep -F -v test example.txt > example.txt.tmp && mv example.txt.tmp example.txt

因为您想要删除一个字符串而不是正则表达式,所以我也添加了-F选项。

您可以使用sed -i,但接着您需要考虑如何找出和/或转义sed定界符,并且sed不支持搜索字符串,因此您需要尝试转义搜索字符串中所有可能的正则表达式字符组合,以使sed将它们视为文字字符(这个过程由于正则表达式字符的位置敏感性质无法自动化),而这只会让你手动命名tmp文件,因为sed内部已经使用了一个。

哦,还有另一种选择-您可以使用GNU awk 4.*进行“原地编辑”。 它也像sed一样在内部使用tmp文件,但它支持字符串操作,因此您不需要尝试转义RE元字符,而且它没有定界符作为语法的一部分需要担心:

awk -i inplace -v rmv="test" '!index($0,rmv)' example.txt

任何grep/sed/awk的解决方案都可以在一万行的文件中飞快地运行。


0
你的grep命令会立即打开输出文件(example.txt)进行写入。这将删除("截断")文件的内容,因此在开始读取文件时,文件是空的。 moreutils软件包中的sponge命令专为这种情况设计。
grep -v test example.txt | sponge example.txt 

这个方法可行,因为“sponge”会缓冲所有的输入,并且只有在接收完输入后才会打开给定的文件(“example.txt”)进行写入。请注意,对于大于你的内存的文件来说,这可能是一个不好的主意!
大多数发行版都提供了Moreutils

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接