如果在同一文件perl / awk中存在匹配,则连接列

时间:2018-01-17 15:01:15

标签: perl awk

我有一个文件如下: FILE1.TXT

1 101 111  BCX A@WWW  123
1 298 306  CCC A@QQQ  234
1 299 308  CCD A@QQQ  
1 299 309  DDD A@ZZZ  345
1 299 309  DDD A@ZZZ  678

如果第5列相同,我试图合并第6列。 输出应为:

1 101 111  BCX A@WWW  123
1 298 306  CCC A@QQQ  234
1 299 308  CCD A@QQQ  234
1 299 309  DDD A@ZZZ  345,678
1 299 309  DDD A@ZZZ  345,678

因此,如果第5列相同,则第6列应该相同。

我正在尝试使我丢失数据,因为如果第6列为空则不会保留该行:

perl -lane 'if($.==1){@a=@F;next} if($F[4]eq$a[4]){$a[5].=";$F[5]";}else{for($i=0;$i<@a;$i++){printf "\t%s",$a[$i]};print"";@a=@F}
            END{for($i=0;$i<@a;$i++){printf "\t%s",$a[$i]};print""}' file1.txt 
    1   101 111 BCX A@WWW   123
    1   298 306 CCC A@QQQ   234;
    1   299 309 DDD A@ZZZ   345;678

如何保留所有行?

4 个答案:

答案 0 :(得分:2)

另一个awk,不改变输入间距

$ awk 'NR==FNR {a[$5]=$5 in a?a[$5] ($6==""?"":","$6):$0; next} 
               {print a[$5]}' file{,}

1 101 111  BCX A@WWW  123
1 298 306  CCC A@QQQ  234
1 298 306  CCC A@QQQ  234
1 299 309  DDD A@ZZZ  345,678
1 299 309  DDD A@ZZZ  345,678

答案 1 :(得分:1)

关注awk可能对您有帮助。

awk 'FNR==NR{a[$5]=a[$5] && $NF~/[0-9]+/?a[$5]","$NF:($NF~/[0-9]+/?$NF:a[$5]);next} {$NF=$5 in a?$NF!~/[0-9]+/?$5 FS a[$5]:a[$5]:$5;} 1'  Input_file  Input_file

编辑: 现在添加一种非单一形式的解决方案。这里也会很快添加解释。

awk '
FNR==NR{
  a[$5]=a[$5] && $NF~/[0-9]+/?a[$5]","$NF:($NF~/[0-9]+/?$NF:a[$5]);
  next
}
{
  $NF=$5 in a?$NF!~/[0-9]+/?$5 FS a[$5]:a[$5]:$5;
}
1
'   Input_file  Input_file

输出如下。

1 101 111 BCX A@WWW 123
1 298 306 CCC A@QQQ 234
1 299 308 CCD A@QQQ 234
1 299 309 DDD A@ZZZ 345,678
1 299 309 DDD A@ZZZ 345,678

答案 2 :(得分:1)

awk 'FNR==NR{
       if($6!="")
       a[$5]=($5 in a ? a[$5] ",":"")$6;
       next
     }
     {
       $6=a[$5]
     }1' infile infile

测试结果:

$ cat f
1 101 111  BCX A@WWW  123
1 298 306  CCC A@QQQ  234
1 299 308  CCD A@QQQ  
1 299 309  DDD A@ZZZ  345
1 299 309  DDD A@ZZZ  678

$ awk 'FNR==NR{if($6!="")a[$5]=($5 in a ? a[$5] ",":"")$6;next}{$6=a[$5]}1' f f
1 101 111 BCX A@WWW 123
1 298 306 CCC A@QQQ 234
1 299 308 CCD A@QQQ 234
1 299 309 DDD A@ZZZ 345,678
1 299 309 DDD A@ZZZ 345,678

答案 3 :(得分:1)

它标记为perl,所以我觉得我们需要一个perl答案:

#!/usr/bin/env perl

use strict;
use warnings;

#read all the rows from STDIN or specified file into an array of arrays. 
my @rows = map { [split] } <>; 

#define a hash to look for lines with matching keys. 
my %value_lookup;
#iterate the rows.
foreach my $row ( @rows ) {
   #check if there's a '6th field' (one of the examples is blank)
   if ( $row -> [5] ) { 
     #push it into a lookup list if there is one. (might only be one element for non dupes. 
     push ( @{$value_lookup{$row -> [4]}}, $row -> [5]);
  }
}

#iterate each row, replacing the 6th element (index 5)
#with whatever is in the value lookup above. 
#or blank, if relevant. 
foreach my $row ( @rows ) {
   $row -> [5] = join ( ",", @{$value_lookup{$row->[4]}});
   #print output, tab separated. 
   print join ("\t", @$row ),"\n";
}

这是一个更详尽的解决方案,因为它适用于任何线路排序。如果你可以依赖它只是连续的线被合并,它会有所简化。

根据您的输入,这会给出:

1   101 111 BCX A@WWW   123
1   298 306 CCC A@QQQ   234
1   299 308 CCD A@QQQ   234
1   299 309 DDD A@ZZZ   345,678
1   299 309 DDD A@ZZZ   345,678