2107

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

4

20 回答 20

3241

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

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

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

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

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

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

直接修改文件(并创建备份)——使用 BSD 和 GNU sed:

sed -i.bak '/pattern to match/d' ./infile
于 2011-03-23T19:48:46.250 回答
688

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

AWK

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

红宝石 (1.9+)

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

Perl

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

外壳(bash 3.2 及更高版本)

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

GNU grep

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

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

sed -n '/pattern/!p' file
于 2011-03-23T23:57:07.830 回答
303

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

例如

sed -i '/pattern/d' filename      

或者

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

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

于 2012-11-02T02:37:06.690 回答
93

使用 GNU 的简单方法sed

sed --in-place '/some string here/d' yourfile
于 2015-01-02T17:56:33.760 回答
43

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

ex +g/match/d -cwq file

在哪里:

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

上面的示例是一种符合 POSIX 的方法,用于根据Unix.SEPOSIX 规范中的ex这篇文章就地编辑文件。


区别sed在于:

sed是一个媒体编辑器,而不是一个文件编辑器。Bash常见问题

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

于 2015-10-17T11:54:43.420 回答
24

我在 Mac 上为此苦苦挣扎。另外,我需要使用变量替换来做到这一点。

所以我用:

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

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

''从这个评论中挑选了。

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

于 2016-03-09T15:39:31.243 回答
20

你也可以使用这个:

 grep -v 'pattern' filename

这里-v将只打印您的模式以外的内容(这意味着反转匹配)。

于 2015-03-28T07:11:29.300 回答
15

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

echo "$(grep -v "pattern" filename)" >filename
于 2015-06-13T19:24:59.060 回答
15

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

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

以下是命令和时间:

time sed -i "/CDGA_00004.pdbqt.gz.tar/d" /tmp/input.txt

real    0m0.711s
user    0m0.179s
sys     0m0.530s

time perl -ni -e 'print unless /CDGA_00004.pdbqt.gz.tar/' /tmp/input.txt

real    0m0.105s
user    0m0.088s
sys     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.046s
user    0m0.014s
sys     0m0.019s
于 2017-03-19T12:45:18.137 回答
9

赛德:

AWK:

GREP:

于 2016-08-25T08:21:57.323 回答
5
perl -i    -nle'/regexp/||print' file1 file2 file3
perl -i.bk -nle'/regexp/||print' file1 file2 file3

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

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

于 2014-06-30T14:59:17.027 回答
5

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

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

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

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

于 2020-09-02T01:49:27.497 回答
5

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

grep -rl 'text_to_search' . | xargs sed -i '/text_to_search/d'
于 2021-02-26T16:34:17.827 回答
3

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

于 2016-09-16T23:51:31.040 回答
2

以防万一有人想对字符串进行精确匹配,您可以使用-wgrep - w 中的标志作为整体。也就是说,例如,如果您想删除编号为 11 的行,但保留编号为 111 的行:

-bash-4.1$ head file
1
11
111

-bash-4.1$ grep -v "11" file
1

-bash-4.1$ grep -w -v "11" file
1
111

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

grep -w -v -f blacklist file
于 2017-03-02T10:45:39.187 回答
2
cat filename | grep -v "pattern" > filename.1
mv filename.1 filename
于 2018-05-31T11:59:14.193 回答
2

奇怪的是,接受的答案实际上并没有直接回答问题。该问题询问有关使用 sed 替换字符串的问题,但答案似乎预设了如何将任意字符串转换为正则表达式的知识。

许多编程语言库都具有执行这种转换的功能,例如

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" 

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

于 2020-10-23T00:00:27.793 回答
1

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

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一次显示一页的文本。

于 2020-02-27T20:19:32.543 回答
0

您可以使用 good olded与使用. 在这种情况下,最大的区别在于它通过标准输入获取命令,而不是像can 这样的命令行参数。在脚本中使用它时,通常的方法是使用管道将命令传递给它:exedexprintf

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

或使用heredoc:

ed -s filename <<EOF
g/pattern/d
w
EOF
于 2020-03-19T14:21:01.327 回答
0

我发现大多数答案对我没有用,如果您使用 vim,我发现这非常简单明了:

:g/<pattern>/d

来源

于 2021-12-25T20:40:35.780 回答