删除输入文件中的行,不包括另一个文件中列出的模式

时间:2013-10-09 20:43:12

标签: perl sed awk grep

我想从输入文件中删除与排除文件中列出的任何模式匹配的行。

输入文件非常庞大(~500 MB),所以我也在寻找有效的解决方案。

请注意,下面的示例只是一个示例,排除可能包含复杂的模式,包括特殊字符,例如/

包含排除列表的文件(例外

Jun
Jul
Aug

输入文件( infile

Jan 02, 2013
Jul 02, 1988
Feb 02, 1988
Jun 02, 1988
Feb 02, 1988
Aug 02, 1988
Jan 02, 2013
Sep 02, 1988
Mar 02, 1988
Jun 02, 1988
Nov 02, 1988

所需输出( outfile

Jan 02, 2013
Feb 02, 1988
Feb 02, 1988
Jan 02, 2013
Sep 02, 1988
Mar 02, 1988
Nov 02, 1988

我可以使用以下命令,给定排除列表,它工作正常。

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;

我希望听到有关其效率的不同方法的反馈。正如我之前提到的,由于我的输入文件很大,文件数量也很大,下一点我担心的是运行时间。

4 个答案:

答案 0 :(得分:4)

此计划应符合您的目的。它的工作原理是通过使用交替运算符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;
}

<强>输出

Jan 02, 2013
Feb 02, 1988
Feb 02, 1988
Jan 02, 2013
Sep 02, 1988
Mar 02, 1988
Nov 02, 1988

答案 1 :(得分:2)

对于您的示例,此行有效:

grep -vf exception infile

答案 2 :(得分:1)

grep -vf patternfile 

应该与unix命令相同。

答案 3 :(得分:0)

为什么不在内部阅读和过滤,而不是走出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);