Perl 如何打印重复超过六次的文件中的行
我有一个包含如下所示数据的文件。第一个逗号分隔的字段可以重复任意次数,我只想打印第六次重复该字段任何值后的行 例如,有八个字段的第一个字段是Perl 如何打印重复超过六次的文件中的行,perl,unix,awk,nawk,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
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
1111111,gggggggg,14
1111111,hhhhhhhh,14
2222222,gggggggg,14
3333333,gggggggg,14
3333333,hhhhhhhh,14
我尝试的是将第2和第3个字段与第1个字段相对应,这样我就可以在$7
或$8
字段上使用nawk
#!/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
使用awk(filter.awk):
使用:
awk -f filter.awk input_file
假设数据中的点应该是逗号,这个Perl命令将执行您要求的操作
perl -aF, -ne 'print if ++$n{$F[0]} > 6' myfile
输出
$perl-F','-ane'打印,除非$seen{$F[0]}++<6'file.txt
解释
启用自动拆分模式,-a
指定-F','
作为拆分标记,结果列表存储在','
中@F
启用隐式逐行循环-n
以Perl代码的形式执行以下参数(-e
)“…”
跟踪第一个字段的显示次数%seed
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);
#/usr/bin/perl
严格使用;
使用警告;
我的$count=0;
我的$prev=“”;
打开(MYFILE,'temp');
而(){
my@a=拆分(/,/);
如果($prev==$a[0])
{
$count++;
如果($count>6)
{
打印“$”;
}
}
其他的
{
$prev=$a[0];
$count=1;
}
}
关闭(MYFILE);
如果您的记录无序
i、 e.您的输入中可能会随机分布“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脚本由一系列条件{action;}
块组成。如果缺少条件,则对每一行应用操作。如果动作缺失,则暗示为print代码>。因此,只包含一个条件的awk脚本将打印该条件计算为true的每个输入行
在这种情况下,我们的条件也包含动作的元素。它增加了关联数组中的元素,其中键是第一个字段。无论条件的计算结果是否为true,增量都会发生。此外,将++
放在变量前面而不是后面会导致增量发生在求值之前而不是之后。(我说的是++var
和var++
之间的区别)如果结果递增的数组元素大于6,则条件求值为true,从而导致打印行
这在功能上等同于其他答案中的perl
解决方案,但由于awk脚本的性质,它甚至更紧凑(可以说)更简单。当然,它可能会更快。(在我刚才的非正式测试中,上面的awk脚本的执行速度是另一个答案中的等效perl脚本的两倍多,在0.23秒的用户时间内处理250000行输入,而在perl中则是0.61秒。)
如果您的记录已订购
i、 e.您所有的“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匹配,而不是处理可能随机分布在整个输入中的匹配行时,才适用。我只是将第二个和第三个字段与第一个字段进行转置,这样我就可以在7美元或8美元的范围内工作了/usr/bin/ksh awk-F“,“{a[$1];b[$1]=b[$1]”,“$2C[$1]=c[$1]”,“$3}END{for(i in a){print i”,“b[i],“c[i]}”file>output.txt请不要在评论中发布代码;改为编辑您的问题。我在您的数据或代码中未看到任何字段$7
或$8
。为什么此问题已关闭?它描述了一个问题,提供了输入数据、预期结果和OP的尝试。实际上,似乎比我见过的许多问题都好。如果解决方案正确,为什么要投反对票?博罗丁,我在发布时没有注意到你的答案,对此表示抱歉!这仅在记录已排序的情况下有效。不管怎样,戈蒂的答案都是有效的。你的作品只有在记录被订购的情况下才有效——ghoti的作品无论它们是否被订购,因此它更灵活。但是his的缺点是在数组中积累数据,这对于非常大的输入可能是一个问题。IMHO,根据给定的示例和措辞,减少无序重复是不正确的。我想我们需要OP的澄清!)@丹尼斯·威廉姆森:不-$seen{$F[0]}++
在第一次通过时将0
<代码>0
至5
包含六个元素。
$ awk -F, '++a[$1] > 6' input.txt
1111111,gggggggg,14
1111111,hhhhhhhh,14
2222222,gggggggg,14
3333333,gggggggg,14
3333333,hhhhhhhh,14
$ 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