如何使用sed删除包含特定字符串的文本文件中的所有行?
要删除行并将输出打印到标准输出:
1
| sed '/pattern to match/d' ./infile |
要直接修改文件:
1
| sed -i '/pattern to match/d' ./infile |
要直接修改文件(并创建备份):
1
| sed -i.bak '/pattern to match/d' ./infile |
对于Mac OS X和FreeBSD用户:
1
| sed -i '' '/pattern/d' ./infile |
- 谢谢,但它似乎并没有将其从文件中删除,只是打印出文本文件内容而不使用该字符串。
- @时钟:是的,您需要将输出重定向到一个新的文件,比如sed '/pattern to match/d' ./infile > ./newfile,或者如果您想进行就地编辑,那么您可以像在sed -i '/pattern to match/d' ./infile中那样将-i标志添加到sed。注意,-i标志需要GNU SED,不可移植。
- 我怎么知道我有什么版本的SED?GNU还是非GNU?
- 对于某些风格的SED,SED的"-i"标志需要提供扩展。(例如,sed -i.backup '/pattern to match/d' ./infile使我了解了在位编辑。
- @更好的是,不要对任何不受版本控制的文件应用像sed这样的命令。
- 对于MacOSX用户来说还有一个注意事项:出于某种原因,-i标志要求传递一个参数,即使它只是一个空字符串,比如sed -i '' '/pattern/d' ./infile。
- @格林盖伊见上面埃维利斯的评论。我还没有Mac电脑,但我会做出一个有教育意义的猜测,你可以做-i 'bak'或-i.bak。
- 我不知道为什么,但最少的命令导致了一个空文件:(
- 对于GNU SED 4,2,2,-i""根本不起作用。然后,它将要匹配的模式作为文件名。只需删除""。
- @马特谢谢你的更新。我的原始答案不包含空引号部分,由于与sed的OSX版本不兼容,因此社区编辑了答案。希望这个更新后的答案对两者都是通用的;它当然适用于GNU sed4.2.2。
- 在Ubuntu sed -i.bak"/str/d" ./infile上,删除整个文件。
- 请注意,如果您的模式将包含正斜杠,则可以使用备用模式分隔符,但必须转义第一个模式分隔符,例如:sed -i.bak"\#$pattern_variable_containing_slashes#d" ./infile。
- @天哪,更好的办法是做sed -i -e '/pattern/d' files..。需要额外参数ed的原因是因为-i将模式作为参数。
- 回写文件似乎需要一个中间临时文件:sed '/pattern to match/d' ./infile > temp && mv temp infile。
- @Rahulmulmulia是的,请参阅此答案顶部的第二条评论。
- 如果我想查找以"e1"(而不是"e11"或"e12")结尾的模式,我该怎么做?
- @Aishwaryakulkarni您将用"$"作为'/模式锚定您的比赛,结束于e1$/'
- 那么像SED'/e1$/d'文件?
- 如何使用sed -i而不打印输出到标准输出?
- @纸板箱。Swing the -i不应按其性质打印到stdout。
- 请注意,"要匹配的模式"区分大小写。
- 注意:对于想要编辑大量文件的人来说:sed写的是一个临时文件。它不是真正的"到位"。如果没有足够的磁盘空间,您将a)磁盘空间不足,b)必须手动删除临时文件。
- 对于MacOSX,一行新行将被附加到没有任何匹配的文件中,这一点都不好!
除sed外,还有许多其他方法可以删除具有特定字符串的行:
AWK
1
| awk '!/pattern/' file > temp && mv temp file |
红宝石(1.9 +)
1
| ruby -i.bak -ne 'print if not /test/' file |
珀尔
1
| perl -ni.bak -e"print unless /pattern/" file |
Shell(bash 3.2及更高版本)
1 2 3 4 5
| while read -r line
do
[[ ! $line =~ pattern ]] && echo"$line"
done <file > o
mv o file |
GNU-GRIP
1
| grep -v"pattern" file > temp && mv temp file |
当然,sed(打印反转比实际删除快):
1
| sed -n '/pattern/!p' file |
- 如何删除一条带图案的特定线条,以及它正上方的线条?我有罚款,在不同的数据之间有数千行这样的行。
- 在OS/X上,shell变体不保留前导空格,但是grep-v变体对我很有效。
- sed的例子有不同的行为,它只是greps!它应该类似于sed -n -i '/pattern/!p' file。
- 当每一行与模式匹配时,grep版本不起作用。更好的做法:grep -v"pattern" file > temp; mv temp file这可能适用于其他一些示例,具体取决于返回值。
- "打印反转比实际删除更快"-不在我的机器上(2012 MacBook Air,OS X 10.13.2)。创建文件:seq -f %f 10000000 >foo.txt。塞德:time sed -i '' '/6543210/d' foo.txt真的0米9.294秒。塞德!P:time sed -i '' -n '/6543210/!p' foo.txtreal 0m13.671s(对于较小的文件,差异较大)。
- 是否可以保留文本文件的第一行,然后对所有其他行应用删除操作?(对于awk选项)@peter mortensen
- @paulbeusterien如果要保留前导和尾随空格,只需使用while IFS= read -r line(此行为与OS/X无关,这在所有符合POSIX的shell中都是正常的)
您可以使用sed替换文件中的行。但是,它似乎比将grep用于将反向文件转换为第二个文件,然后将第二个文件移到原始文件上慢得多。
例如
1
| sed -i '/pattern/d' filename |
或
1
| grep -v"pattern" filename > filename2; mv filename2 filename |
不管怎样,第一个命令在我的机器上需要3倍的时间。
- 投票决定你的答案,仅仅因为你尝试了一个性能比较!
- +1用于提供用grep行覆盖当前文件的选项。
- 出于某种原因,Mac OS SED版本(BSD)不接受零长度备份文件名,但如果提供了零长度备份文件名,则可以正常工作。
- 第二个"grep"解决方案也更适合大型文件
- 我很好奇如果是sed '/pattern/d' filename > filename2; mv filename2 filename,性能会有什么不同。
- (使用Ubuntu的/usr/share/dict/words)grep和mv:0.010s sed到位:0.197s sed和mv:0.031s
- 如何删除任何文件中包含文本的行?假设我在/var/www/html/中,想删除任何PHP文件中包含"hacker.com"的行吗?
- 找到。-键入f-name"*.php"xargs-i file sed-i'/hacker.com/d'文件
- cat filename | grep -v"pattern"> filename
使用GNU sed可以很容易地做到这一点:
1
| sed --in-place '/some string here/d' yourfile |
- 对于那些偶然发现这个问答线程并且不熟悉shell脚本的人来说,这是一个方便的提示:短选项对于命令行一次性使用是很好的,但是长选项在脚本中应该是首选的,因为它们更具可读性。
- +1代表就地标志。我需要在受权限保护的文件上测试这一点。(必须进行一些用户清理。)
- 请注意,long选项仅在GNU SED上可用。Mac和BSD用户需要安装GSED才能这样做。
您可以考虑使用ex(这是一个标准的基于Unix命令的编辑器):
在哪里?
- +执行给定的ex命令(man ex),与-c执行wq(写入和退出)
- g/match/d—用给定的match删除行的ex命令,见:g的幂
上面的示例是一个符合POSIX的方法,用于根据本文的unix.se和ex的POSIX规范就地编辑文件。
与sed的区别在于:
sed is a Stream EDitor, not a file editor.BashFAQ
除非您喜欢不可移植的代码、I/O开销和其他一些不良的副作用。因此,基本上,一些参数(如in-place/-i)是非标准的freebsd扩展,可能在其他操作系统上不可用。
- 太好了…当我做man ex时,它给了我一个支持vim的人,似乎ex是Vim的一部分。如果我理解正确,这意味着match的模式语法是vimregex.com,它与posix和pcre风格相似但不同?
- :g 是posix兼容命令,但有一些细微的差异。我想PCRE是基于它的。
我在Mac上苦苦挣扎。另外,我需要使用变量替换来完成它。
所以我用:
sed -i ''"/$pattern/d" $file
其中$file是需要删除的文件,$pattern是需要匹配删除的模式。
我从这个评论中选择了''。
这里要注意的是在"/$pattern/d"中使用双引号。当我们使用单引号时,变量将不起作用。
- mac sed要求在-i后面有一个参数,所以如果不需要备份,还需要添加一个空字符串:-i ''。
要获得与grep类似的就地结果,可以执行以下操作:
1
| echo"$(grep -v"pattern" filename)">filename |
- 这只对bash壳或类似壳(而不是tcsh壳)有好处。
我用一个包含大约345000行的文件做了一个小基准。在这种情况下,使用grep方法的速度大约是使用sed方法的15倍。
我尝试过在设置lc_all=c和不设置lc_all=c的情况下,似乎并没有显著改变计时。搜索字符串(cdga_00004.pdbqt.gz.tar)位于文件的中间。
以下是命令和时间:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| 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 |
- 你在哪个月台?您使用哪种版本的SED/Perl/grep?
- 我使用的平台是Linux(Gentoo)。SED版本是GNU SED v4.2.2,Perl版本是Perl5(我不知道测试时使用的是哪个版本),GREP(GNU)是3.0版。
您还可以使用:
1
| grep -v 'pattern' filename |
这里,-v只打印您的模式以外的内容(这意味着反转匹配)。
塞德:
- '/James\|John/d'
- -n '/James\|John/!p'
AWK:
- '!/James|John/'
- /James|John/ {next;} {print}
GRP:
echo -e"/thing_to_delete
dd\033:x
" | vim file_to_edit.txt
1 2
| perl -i -nle'/regexp/||print' file1 file2 file3
perl -i.bk -nle'/regexp/||print' file1 file2 file3 |
第一个命令编辑就地的文件(-i)。
第二个命令执行相同的操作,但通过在文件名中添加.bk来保留原始文件的副本或备份(可以将.bk更改为任何内容)。
1 2
| cat filename | grep -v"pattern"> filename.1
mv filename.1 filename |
为了防止有人想要对字符串进行精确匹配,您可以使用grep-w中的-w标志作为整体。例如,如果要删除编号为11的行,但保留编号为111的行:
1 2 3 4 5 6 7 8 9 10 11
| -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标志一起使用。如果"黑名单"是一个文件,每行上有多个模式,您想从"文件"中删除:
1
| grep -w -v -f blacklist file |
- 有点误导。-w, --word-regexp Select only those lines containing matches that form whole words.对-x, --line-regexp Select only those matches that exactly match the whole line. For a regular expression pattern, this is like parenthesizing the pattern and then surrounding it with ^ and $.的比较