3

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

例如,有八个字段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

我尝试过的是相对于第一个转置第二个和第三个字段,以便我可以在ornawk的字段上使用$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
4

5 回答 5

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 脚本将打印该条件评估为真的每个输入行。

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

这在功能上等同perl于其他答案中的解决方案,但由于 awk 脚本的性质,它甚至更严格并且(可以说)更简单。当然,它可能会更快。(在我刚才的非正式测试中,上面的 awk 脚本的执行速度是另一个答案的等效 perl 脚本的两倍多,在 0.23 秒的用户时间内处理 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 的连续行集,而不是处理可能在整个输入中随机分布的匹配行。

于 2012-09-06T13:24:32.563 回答
6
$ perl -F',' -ane 'print unless $seen{ $F[0] }++ < 6' file.txt

解释

  • -a启用自动拆分模式,-F','指定','为拆分标记,结果列表存储在@F结果中
  • -n启用隐式逐行循环
  • -e执行以下参数('...'在这种情况下)作为 Perl 代码
  • %seen跟踪看到第一个字段的次数
于 2012-09-06T13:20:00.970 回答
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
于 2012-09-06T13:13:01.413 回答
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
于 2012-09-06T12:45:15.980 回答
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);
于 2012-09-06T13:22:18.557 回答