4

首先让我说我不想只打印重复的行,也不想删除它们。

我正在尝试将 grep 与模式文件一起使用来解析大型数据文件。

例如,Pattern 文件可能如下所示:

1243
1234
1234
1234
1354
1356
1356
1677

等具有更多单一和重复的条目。

输入数据文件可能如下所示:

aatta   1243    qqqqqq
yyyyy   1234    vvvvvv
ttttt   1555    bbbbbb
ppppp   1354    pppppp
yyyyy   3333    zzzzzz
qqqqq   1677    eeeeee
iiiii   4444    iiiiii

等27000行。

当我使用

grep -f 'Patternfile.txt' 'Inputfile.txt' > 'Outputfile.txt'

我得到一个类似于这样的输出文件:

aatta   1243    qqqqqq
yyyyy   1234    vvvvvv
ppppp   1354    pppppp

我怎样才能让它也报告重复项,所以我最终得到这样的结果?:

aatta   1243    qqqqqq
yyyyy   1234    vvvvvv
yyyyy   1234    vvvvvv
yyyyy   1234    vvvvvv
ppppp   1354    pppppp


qqqqq   1677    zzzzzz

此外,如果模式文件中的查询与输入文件中的子字符串不匹配,我还想打印一个空行。

谢谢!

4

2 回答 2

2

一种解决方案,不是使用grep,而是使用perl

使用patternfile.txtinputfile.txt使用原始帖子的数据。的下一个内容script.pl应该做的工作(我假设要匹配的字符串是第二列,否则应该修改为使用 aregexp代替。这种方式更快):

use warnings;
use strict;

## Check arguments.
die qq[Usage: perl $0 <pattern-file> <input-file>\n] unless @ARGV == 2;

## Open input files.
open my $pattern_fh, qq[<], shift @ARGV or die qq[Cannot open pattern file\n];
open my $input_fh, qq[<], shift @ARGV or die qq[Cannot open input file\n];

## Hash to save patterns.
my (%pattern, %input);

## Read each pattern and save how many times appear in the file.
while ( <$pattern_fh> ) { 
    chomp;
    if ( exists $pattern{ $_ } ) { 
        $pattern{ $_ }->[1]++;
    }   
    else {
        $pattern{ $_ } = [ $., 1 ];
    }   
}

## Read file with data and save them in another hash.
while ( <$input_fh> ) { 
    chomp;
    my @f = split;
    $input{ $f[1] } = $_; 
}

## For each pattern, search it in the data file. If it appears, print line those
## many times saved previously, otherwise print a blank line.
for my $p ( sort { $pattern{ $a }->[0] <=> $pattern{ $b }->[0] } keys %pattern ) { 
    if ( $input{ $p } ) { 
        printf qq[%s\n], $input{ $p } for ( 1 .. $pattern{ $p }->[1] );
    }   
    else {
         # Old behaviour.
         # printf qq[\n];

         # New requirement.
         printf qq[\n] for ( 1 .. $pattern{ $p }->[1] );
    }   
}

像这样运行它:

perl script.pl patternfile.txt inputfile.txt

并给出下一个输出:

aatta   1243    qqqqqq
yyyyy   1234    vvvvvv
yyyyy   1234    vvvvvv
yyyyy   1234    vvvvvv
ppppp   1354    pppppp


qqqqq   1677    eeeeee
于 2012-03-26T20:09:59.550 回答
1

您不是很喜欢grep模式,而是将输入中的数据左连接到模式中的数据。

您可以(大多数情况下)使用 完成此操作join,这是一个方便的 Unix 实用程序,因为我一直在尝试解决与您类似的问题,所以我已经非常了解了。

不过,有一些小的差异。

首先是命令:

join -a 1 -2 2 <(sort Patternfile.txt) <(sort -k2,3 Inputfile.txt)

和解释:

  • -a 1意味着还包括文件 1 ( Patternfile.txt ) 中不可连接的行。我添加这个是因为你想为不匹配的行包含“空白”行,这是我能得到的最接近的。
  • -2 2表示加入文件 2 的字段 2(您可以为-1 FIELD和设置字段-2 FIELD,默认为字段 1)。这是因为您在Inputfile.txt中加入的键位于第二列
  • <(sort Patternfile.txt)— 文件必须在连接字段上排序,连接才能正常工作。
  • <(sort -k2,2 Inputfile.txt)— 将输入文件从键 2 排序到键 2,包括

输出:

1234 yyyyy vvvvvv
1234 yyyyy vvvvvv
1234 yyyyy vvvvvv
1243 aatta qqqqqq
1354 ppppp pppppp
1356
1356
1677 qqqqq eeeeee

差异

您指定的输出与此结果之间的细微差别:

  • 它按键顺序排序。
  • 不可连接的行仍然包含它们的原始键。如果这是一个问题,您可以通过一个简单的管道清除不匹配的行awk

    ... | awk '{ if ($2 != "") print; else print ""  }'
    
于 2013-09-24T20:56:31.990 回答