Объединение двух файлов с помощью awk
у меня есть два файла, как показано ниже, которые являются разделителями табуляции:
на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?
2 ответов
вот один подход с использованием awk
:
$ awk 'NR==FNR{a[,]=OFS;next}{=a[,];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[,]=OFS # Create entry in array with fields 3 and 4 as the key
next # Grab the next line (don't process the next block)
=a[,] # Assign the looked up value to field 6 (+rebuild records)
print # Print the current line & the matching entry from fileb ()
OFS='\t' # Seperate each field with a single TAB on output
Edit:
для задачи 3 поля вы просто добавляете дополнительное поле:
$ awk 'NR==FNR{a[,,]=OFS;next}{=a[,,];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
можно использовать 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/ \+\([^ ]\+\) \+\([^ ]\+\)/ :/' 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";
}