如何从重复六次以上的文件中打印行

时间:2012-09-06 12:25:42

标签: perl unix awk nawk

我有一个包含以下数据的文件。第一个以逗号分隔的字段可以重复任意次,并且我想在第六次重复此字段的任何值后仅打印行

例如,有八个字段1111111作为第一个字段,我想只打印这些记录中的第七个和第八个

输入文件:

1111111,aaaaaaaa,14
1111111,bbbbbbbb,14
1111111,cccccccc,14
1111111,dddddddd,14
1111111,eeeeeeee,14
1111111,ffffffff,14
1111111,gggggggg,14
1111111,hhhhhhhh,14
2222222,aaaaaaaa,14
2222222,bbbbbbbb,14
2222222,cccccccc,14
2222222,dddddddd,14
2222222,eeeeeeee,14
2222222,ffffffff,14
2222222,gggggggg,14
3333333,aaaaaaaa,14
3333333,bbbbbbbb,14
3333333,cccccccc,14
3333333,dddddddd,14
3333333,eeeeeeee,14
3333333,ffffffff,14
3333333,gggggggg,14
3333333,hhhhhhhh,14

输出:

1111111,gggggggg,14
1111111,hhhhhhhh,14
2222222,gggggggg,14
3333333,gggggggg,14
3333333,hhhhhhhh,14

我试过的是转发第1个第2和第3个字段,这样我就可以在nawk$7

的字段上使用$8
#!/usr/bin/ksh awk -F"," '{ a[$1]; b[$1]=b[$1]","$2 c[$1]=c[$1]","$3} END{ for(i in a){ print i","b[i]","c[i]} } ' file > output.txt

5 个答案:

答案 0 :(得分:7)

如果您的记录无序

即。您可以在整个输入中随机分配“1111111”项目:

$ awk -F, '++a[$1] > 6' input.txt
1111111,gggggggg,14
1111111,hhhhhhhh,14
2222222,gggggggg,14
3333333,gggggggg,14
3333333,hhhhhhhh,14

这是如何运作的?

如您所知,awk的-F选项设置分隔符。如果它不是一个特殊的角色,就没有必要引用它。

Awk脚本由一系列condition { action; }块组成。如果缺少条件,则对每一行应用操作。如果缺少该操作,则隐含为print;。因此,仅包含条件的awk脚本将打印该条件评估为真的每个输入行。

在这种情况下,我们的条件也包含一个动作的元素。它,它增加了一个关联数组的元素,其中键是你的第一个字段。无论条件是否为真,都会发生增量。此外,将++ 提前而不是跟随变量会导致增量在评估之前发生而不是之后 / em>它。 (我在谈论++varvar++之间的区别。)如果结果递增的数组元素大于6,则条件计算结果为true,导致行打印。

这在功能上等同于其他答案中的perl解决方案,但由于awk脚本的性质更加严格且(可以说)更简单。当然,它可能会更快。 (在我刚才的非正式测试中,上面的awk脚本执行的速度是另一个答案的等效perl脚本的两倍多,在0.23s的用户时间内处理250000行输入,而在perl中处理0.61秒。)

如果您的记录已订购

即。所有“1111111”行都在一起:

$ awk -F, '$1!=f{c=0;f=$1} ++c>6' input.txt
1111111,gggggggg,14
1111111,hhhhhhhh,14
2222222,gggggggg,14
3333333,gggggggg,14
3333333,hhhhhhhh,14

这是如何运作的?

  • 如果我们与上次不同的$ 1(在第一行也是如此),我们重置我们的计数器并将$ 1保存到变量以供将来比较。
  • 然后,如果计数器超过6,我们递增计数器并打印行(隐式)。

这样做的好处是不会使用数组占用内存,但只有当你的目标是使用常见的$ 1匹配顺序的行集而不是处理可能在整个输入中随机分布的匹配行时,它才适用。

答案 1 :(得分:6)

$ perl -F',' -ane 'print unless $seen{ $F[0] }++ < 6' file.txt

<强>解释

  • -a启用自动分段模式,-F','指定','作为拆分令牌,结果列表存储在@F中作为结果
  • -n启用隐式逐行循环
  • -e执行以下参数(在本例中为'...')作为Perl代码
  • %seen跟踪第一个字段的显示次数

答案 2 :(得分:4)

假设数据中的点应该是逗号,这个Perl命令将执行您所要求的

perl -aF, -ne 'print if ++$n{$F[0]} > 6' myfile

<强>输出

1111111,gggggggg,14
1111111,hhhhhhhh,14
2222222,gggggggg,14
3333333,gggggggg,14
3333333,hhhhhhhh,14

答案 3 :(得分:1)

使用awk(filter.awk):

BEGIN    { FS = "[,.]"          }   
o == $1  { cnt++                } 
o != $1  { o=$1; cnt = 0;       }
cnt >= 6 { print $0             }

使用:

awk -f filter.awk input_file

答案 4 :(得分:0)

如果您想特别使用awk解决方案,请点击此处:

awk -F, '{if(seen==$1){count++;}else{seen=$1;count=1}if(count>6)print }' file

测试如下:

> awk -F, '{if(seen==$1){count++;}else{seen=$1;count=1}if(count>6)print }' temp
1111111,gggggggg,14
1111111,hhhhhhhh,14
2222222,gggggggg,14
3333333,gggggggg,14
3333333,hhhhhhhh,14

如果您需要perl脚本,请参阅下文:

#!/usr/bin/perl

use strict;
use warnings;

my $count=0;
my $prev="";
open (MYFILE, 'temp');
while (<MYFILE>) {
       my @a=split(/,/);
       if($prev==$a[0])
       {
        $count++;
        if($count>6)
         {
           print "$_";       
          }
        }
        else
        {
        $prev=$a[0];
        $count=1; 
        }

 }
close (MYFILE);