6

我有两个如下所示的文件,它们是制表符分隔的:

档案A

chr1   123 aa b c d
chr1   234 a  b c d
chr1   345 aa b c d
chr1   456 a  b c d
....

文件 B

xxxx  abcd    chr1   123    aa    c    d    e
yyyy  defg    chr1   345    aa    e    f    g
...

我想加入基于 3 列与“chr1”、“123”和“aa”的两个文件,并将文件 B 的前两列添加到文件 A,这样输出如下所示: 输出:

chr1   123    aa    b    c    d    xxxx    abcd
chr1   234    a     b    c    d
chr1   345    aa    b    c    d    yyyy    defg
chr1   456    a    b    c    d

任何人都可以帮助在 awk 中执行此操作。如果可能的话,使用 awk oneliners?

4

2 回答 2

11

这是使用的一种方法awk

$ awk 'NR==FNR{a[$3,$4]=$1OFS$2;next}{$6=a[$1,$2];print}' OFS='\t' fileb filea
chr1    123     a    b    c     xxxx    abcd
chr1    234     a    b    c 
chr1    345     a    b    c     yyyy    defg
chr1    456     a    b    c 

解释:

NR==FNR             # current recond num match the file record num i.e in filea
a[$3,$4]=$1OFS$2    # Create entry in array with fields 3 and 4 as the key
next                # Grab the next line (don't process the next block)
$6=a[$1,$2]         # Assign the looked up value to field 6 (+rebuild records)  
print               # Print the current line & the matching entry from fileb ($6)

OFS='\t'            # Seperate each field with a single TAB on output

编辑:

对于 3 字段问题,您只需添加额外字段:

$ awk 'NR==FNR{a[$3,$4,$5]=$1OFS$2;next}{$6=a[$1,$2,$3];print}' OFS='\t' fileb filea
chr1    123    aa     b      c     xxxx     abcd
chr1    234    a      b      c  
chr1    345    aa     b      c     yyyy     defg
chr1    456    a      b      c 
于 2013-08-06T20:25:02.557 回答
2

您可以使用join,但管道变得如此复杂,切换到更强大的语言(如 Perl)可能会更容易。

join -11 -21 -o1.1,1.2,1.3,1.4,1.5,2.4,2.5 \
     <(sed 's/ \+/:/' fileA | sort) \
     <(sed 's/ \+/:/' fileB | sort) \
 | join -11 -22 -a1 -o1.1,1.2,1.3,1.4,1.5,1.6,1.7,2.5,2.6 \
     - <(sed 's/ \+\([^ ]\+\) \+\([^ ]\+\)/ \1:\2/' fileC | sort -k2) \
 | sed 's/:/ /'

Perl 解决方案,使用哈希来记住所有信息:

#!/usr/bin/perl
use warnings;
use strict;

#             key_start  key_end  keep_from  output
my %files = (A => [0,      1,      2,       [0 .. 3]],
             B => [0,      1,      2,       [-2, -1]],
             C => [1,      2,      3,       [-2, -1]],
            );

my %hash;

for my $file (keys %files) {
    open my $FH, '<', "file$file" or die "file$file: $!";
    while (<$FH>) {
        my @fields = split;
        $hash{"@fields[$files{$file}[0], $files{$file}[1]]"}{$file}
            = [ @fields[$files{$file}[2] .. $#fields] ];
    }
}

for my $key (sort keys %hash) {
    print $key, join(' ', q(),
                     grep defined, map {
                         @{ $hash{$key}{$_} }[@{ $files{$_}[-1] }]
                     } sort keys %files), "\n";
}
于 2012-11-06T20:31:08.427 回答