Perl 删除输入文件中的行,不包括另一个文件中列出的模式
我想从输入文件中删除与排除文件中列出的任何模式匹配的行 输入文件相当大(约500 MB),所以我也在寻找有效的解决方案 请注意,下面的示例只是一个示例,排除可能包含包含特殊字符的复杂模式,例如Perl 删除输入文件中的行,不包括另一个文件中列出的模式,perl,sed,awk,grep,Perl,Sed,Awk,Grep,我想从输入文件中删除与排除文件中列出的任何模式匹配的行 输入文件相当大(约500 MB),所以我也在寻找有效的解决方案 请注意,下面的示例只是一个示例,排除可能包含包含特殊字符的复杂模式,例如/ 包含排除列表的文件(异常) 输入文件(infle) 所需输出(输出文件) 在给定排除列表的情况下,我可以使用下面的命令,并且效果很好 egrep -v "Jun|Jul|Aug" infile > outfile 我的问题是如何从异常文件中获取管道|分隔字符串并将其传递给上面的grep命令?或者
/
包含排除列表的文件(异常)
输入文件(infle)
所需输出(输出文件)
在给定排除列表的情况下,我可以使用下面的命令,并且效果很好
egrep -v "Jun|Jul|Aug" infile > outfile
我的问题是如何从异常文件中获取管道|
分隔字符串并将其传递给上面的grep命令?或者有没有其他最佳方式来实现这一点
我必须将其作为perl
解决方案的一部分来实现,在该解决方案中,进一步的处理是通过哈希实现的。但我对任何linux解决方案都持开放态度,因为我可以在perl脚本中执行这些命令
非常感谢您在这方面的帮助
更新
与此同时,人们正在帮助我解决他们的问题,我可以用perl
编写下面的代码,而且它也起到了作用
#!/usr/bin/perl
use warnings;
use strict;
open my $exfread, '<', "exception" or die $!;
chomp ( my @exclusions = <$exfread> );
close $exfread;
my $ex_str = join '|', @exclusions;
# print $ex_str . "\n";
open my $infread, '<', "infile" or die $!;
open my $outfwrite, '>', "outfile" or die $!;
while (<$infread>) {
next if /${ex_str}/;
print $outfwrite $_;
# do some more processing using hash
}
close $outfwrite;
close $infread;
#/usr/bin/perl
使用警告;
严格使用;
打开我的$exfread,“而不是在Perl之外,为什么不像这样在里面阅读和过滤呢
#!/usr/bin/env perl
use strict;
use warnings;
my $ifile = 'old.txt';
my $ofile = 'new.txt';
open (my $ifh, '<', $ifile) or die $!;
open (my $ofh, '>', $ofile) or die $!;
while (<$ifh>) {
print $ofh $_ unless /^Jun|Jul|Aug/;
}
close ($ifh);
close ($ofh);
#/usr/bin/env perl
严格使用;
使用警告;
my$ifile='old.txt';
my$ofile='new.txt';
打开(我的$ifh,,$ofile)或死亡$!;
而(){
打印$ofh$除非/^Jun | Jul | Aug/;
}
关闭($ifh);
收盘价($ofh);
此程序应适合您的目的。它的工作原理是通过将每一行与交替操作符|
连接,从exception.txt
的内容中形成一个正则表达式。然后使用qr
编译正则表达式
这应该证明是非常快的,因为每行只执行一个正则表达式比较
use strict;
use warnings;
use autodie;
my $regex = do {
open my $in, '<', 'exception.txt';
my @infile = <$in>;
chomp @infile;
local $" = '|';
qr/@infile/;
};
open my $in, '<', 'infile.txt';
open my $out, '>', 'outfile.txt';
while (<$in>) {
print $out $_ unless $_ =~ $regex;
}
对于您的示例,这一行适用于:
grep -vf exception infile
应执行与unix命令相同的操作。感谢您的回复。但我的主要问题是从一个单独的文件中获取搜索模式列表。我知道我可以读取该文件并使用join
。但搜索模式也可以包含/
。请参阅@Borodin solution then。这是完美的一行!谢谢!我应该检查一下mangrep
:(现在接受perl解决方案,但下次一定会在shell脚本中使用它。我认为这个解决方案不担心特殊字符,最好是quotemeta()
它们?类似于:s=join q{124;},map{$=q{124;\\ q}.$.q}\\E}@infle
然后执行qr
?@Birei:绝对不会。在编译正则表达式之前将quotemeta
应用于正则表达式将避开所有反斜杠,并使它们作为文字字符匹配。试试看。@Borodin效果很好!如果您能评论一下perl与grep one linerTrue的使用效率,我将不胜感激。我已经测试过了它意识到我错了:-)但是如何解决字符串中特殊字符的转义呢?@jkshah:我不能评论与Perl相比grep
的效率,但是,正如我在你的问题上所评论的,除非两者都非常低效,它们之间没有什么可选择的。这正是我提供的解决方案,只是您不必要地为输入文件的每一行编译正则表达式。@Borodin看到了您的ans。肯定会尝试的。正如我所说,我的下一个目标将是选择运行时间更短的高效代码。在不同的方法之间几乎没有选择。一个500MB的文件并没有那么大,但从硬盘上读取它大约需要10秒钟,而写入相同的数据则需要大致相同的时间。相比之下,检查每行内容的处理时间微不足道,因此无论您选择哪种方法,运行时间都大约为20秒。@Borodin感谢您的详细解释。我知道解析数据并将其存储在另一个文件中不会花费太多时间。请注意,我必须对过滤后的数据创建一个大的散列。可能是我做这件事效率低下,因为它花了大约5分钟。您所描述的只是根据异常
过滤infle
到outfile
。这应该只需要几秒钟。很明显,我不能评论你可能正在做的任何事情。
#!/usr/bin/env perl
use strict;
use warnings;
my $ifile = 'old.txt';
my $ofile = 'new.txt';
open (my $ifh, '<', $ifile) or die $!;
open (my $ofh, '>', $ofile) or die $!;
while (<$ifh>) {
print $ofh $_ unless /^Jun|Jul|Aug/;
}
close ($ifh);
close ($ofh);
use strict;
use warnings;
use autodie;
my $regex = do {
open my $in, '<', 'exception.txt';
my @infile = <$in>;
chomp @infile;
local $" = '|';
qr/@infile/;
};
open my $in, '<', 'infile.txt';
open my $out, '>', 'outfile.txt';
while (<$in>) {
print $out $_ unless $_ =~ $regex;
}
Jan 02, 2013
Feb 02, 1988
Feb 02, 1988
Jan 02, 2013
Sep 02, 1988
Mar 02, 1988
Nov 02, 1988
grep -vf exception infile
grep -vf patternfile