如何从文本文件中删除包含特定字符串的所有行?

如何使用ed删除文本文件中包含特定字符串的所有行?

2325118 次浏览

要删除该行并将输出打印为标准输出:

sed '/pattern to match/d' ./infile

要直接修改文件-不适用于BSD ses:

sed -i '/pattern to match/d' ./infile

相同,但对于BSD ses(Mac OS X和FreeBSD)-不适用于GNU ses:

sed -i '' '/pattern to match/d' ./infile

要直接修改文件(并创建备份)-适用于BSD和GNU ses:

sed -i.bak '/pattern to match/d' ./infile

除了sed之外,还有许多其他方法可以删除具有特定字符串的行:

AWK

awk '!/pattern/' file > temp && mv temp file

Ruby(1.9+)

ruby -i.bak -ne 'print if not /test/' file

perl

perl -ni.bak -e "print unless /pattern/" file

Shell(bash 3.2及更高版本)

while read -r linedo[[ ! $line =~ pattern ]] && echo "$line"done <file > omv o file

gnugrep

grep -v "pattern" file > temp && mv temp file

当然sed(打印逆比实际删除更快):

sed -n '/pattern/!p' file

您可以使用ed来替换文件中的行。但是,它似乎比使用grep进行反向转换到第二个文件然后将第二个文件移动到原始文件上要慢得多。

e. g.

sed -i '/pattern/d' filename

grep -v "pattern" filename > filename2; mv filename2 filename

无论如何,第一个命令在我的机器上需要3倍的时间。

perl -i    -nle'/regexp/||print' file1 file2 file3perl -i.bk -nle'/regexp/||print' file1 file2 file3

第一个命令在原地(-i)编辑文件。

第二个命令做同样的事情,但通过在文件名中添加. bk来保留原始文件的副本或备份(. bk可以更改为任何内容)。

简单的方法是使用GNUsed

sed --in-place '/some string here/d' yourfile

你也可以使用这个:

 grep -v 'pattern' filename

这里-v将只打印除您的模式之外的其他模式(这意味着反转匹配)。

要获得类似于grep的inplace结果,您可以这样做:

echo "$(grep -v "pattern" filename)" >filename

您可以考虑使用#0(这是一个标准的基于Unix命令的编辑器):

ex +g/match/d -cwq file

在哪里:

  • +执行给定的Ex命令(man ex),与-c执行wq(写入并退出)相同
  • g/match/d-Ex命令删除给定match的行,请参阅:g的幂

上面的示例是一个POSIX兼容的方法,用于根据发表在Unix.SE#0的POSIX规范就地编辑文件。


sed的区别在于:

sedStreamEDitor,不是文件编辑器。BashFAQ

除非你喜欢不可移植的代码、I/O开销和其他一些不好的副作用。所以基本上有些参数(比如in-place/-i)是非标准的FreeBSD扩展,可能在其他操作系统上不可用。

我在Mac上一直在努力解决这个问题。另外,我需要使用变量替换来做到这一点。

所以我用了:

sed -i '' "/$pattern/d" $file

其中$file是需要删除的文件,$pattern是要匹配删除的模式。

我从这个评论中选择了''

这里要注意的是在"/$pattern/d"中使用双引号。当我们使用单引号时,变量将不起作用。

echo-e"/thing_to_delete\ndd\033: x\n"|vimfile_to_edit.txt

如果有人想对字符串的完全匹配执行此操作,您可以在grep-w中使用-w标志作为整体。也就是说,例如,如果您想删除编号为11的行,但保留编号为111的行:

-bash-4.1$ head file111111
-bash-4.1$ grep -v "11" file1
-bash-4.1$ grep -w -v "11" file1111

如果您想一次排除多个确切的模式,它也适用于-f标志。如果“黑名单”是一个文件,每行都有多个模式,您想从“文件”中删除:

grep -w -v -f blacklist file

我用一个包含大约345000行的文件做了一个小基准测试。在这种情况下,grep的方法似乎比sed方法快15倍左右。

我已经尝试了使用和不使用设置LC_ALL=C,它似乎没有显着改变时间。搜索字符串(CDGA_00004.pdbqt.gz.tar)位于文件中间的某个地方。

以下是命令和计时:

time sed -i "/CDGA_00004.pdbqt.gz.tar/d" /tmp/input.txt
real    0m0.711suser    0m0.179ssys     0m0.530s
time perl -ni -e 'print unless /CDGA_00004.pdbqt.gz.tar/' /tmp/input.txt
real    0m0.105suser    0m0.088ssys     0m0.016s
time (grep -v CDGA_00004.pdbqt.gz.tar /tmp/input.txt > /tmp/input.tmp; mv /tmp/input.tmp /tmp/input.txt )
real    0m0.046suser    0m0.014ssys     0m0.019s
cat filename | grep -v "pattern" > filename.1mv filename.1 filename

在控制台中显示处理过的文本

cat filename | sed '/text to remove/d'

将处理过的文本保存到文件中

cat filename | sed '/text to remove/d' > newfile

将处理过的文本信息附加到现有文件

cat filename | sed '/text to remove/d' >> newfile

来处理已经处理过的文本,在这种情况下,删除已删除内容的更多行

cat filename | sed '/text to remove/d' | sed '/remove this too/d' | more

| more将一次以一个页面的块显示文本。

您可以使用旧的ed以类似于使用ex的答案的方式编辑文件。在这种情况下,最大的区别在于ed通过标准输入获取其命令,而不是像ex这样的命令行参数。在脚本中使用它时,通常的适应方法是使用printf将命令通过管道传递给它:

printf "%s\n" "g/pattern/d" w | ed -s filename

或者用heldoc:

ed -s filename <<EOFg/pattern/dwEOF

您还可以删除文件中的一系列行。例如,删除SQL文件中的存储过程。

sed '/CREATE PROCEDURE.*/,/END ;/d' sqllines.sql

这将删除CREATE PROCEDURE和END;之间的所有行。

我已经清理了许多sql文件使用这个Sed命令。

奇怪的是,被接受的答案实际上并没有直接回答这个问题。这个问题问的是使用ses来替换字符串,但答案似乎预先假设了如何将任意字符串转换为regex的知识。

许多编程语言库都有一个函数来执行这种转换,例如。

python: re.escape(STRING)ruby: Regexp.escape(STRING)java:  Pattern.quote(STRING)

但是如何在命令行上执行呢?

由于这是一个面向sed的问题,一种方法是使用sed本身:

sed 's/\([\[/({.*+^$?]\)/\\\1/g'

因此,给定一个任意字符串$STRING,我们可以编写如下内容:

re=$(sed 's/\([\[({.*+^$?]\)/\\\1/g' <<< "$STRING")sed "/$re/d" FILE

或者作为一个单行:

 sed "/$(sed 's/\([\[/({.*+^$?]\)/\\\1/g' <<< "$STRING")/d"

如本页其他地方所述的变化。

从所有匹配的文件中删除行

grep -rl 'text_to_search' . | xargs sed -i '/text_to_search/d'

我发现大多数答案对我没有用,如果你使用vim,我发现这很容易和直接:

:g/<pattern>/d

来源

此解决方案用于对多个文件执行相同的操作。

for file in *.txt; do grep -v "Matching Text" $file > temp_file.txt; mv temp_file.txt $file; done