我有一个问题需要合并几个不同的文件。
仅举两个文件*但是Column只是不同的值。 每个文件都有侧面的制表符分隔符。 按ID信息加入所有列。
第一个文件Test.txt
ID ID2 ID3 Name Telephone
1 A + John 011
1 B - Mike 012
2 C + Sam 013
3 A - Jena 014
4 B + Peter 015
第二个文件Test2.txt
ID ID2 ID3 Name Telephone
2 C + Henry 013
3 A - Ho 014
1 A + Jamy 011
1 B - Mark 012
4 B + Jung 015
然后是最终结果
ID ID2 ID3 Name Telephone Name Telephone
1 A + John 011 Jamy 011
1 B - Mike 012 Mark 012
2 C + Sam 013 Henry 013
3 A - Jena 014 Ho 014
4 B + Peter 015 Jung 015
因此,组合取决于ID 1 ID2 ID3,
我尝试使用join之类的 join -a1 -a2 -a3 Test1.txt Test2.txt> Test3.txt
这样的东西但是Performance和多文件连接存在问题 而且我不确定这是否正确加入。
有没有人有最好的想法?
答案 0 :(得分:2)
awk -F"\t" -v OFS="\t" '
{key = $1 SUBSEP $2 SUBSEP $3}
FNR==NR {line[key]=$0; next}
key in line {print line[$1,$2,$3], $4, $5}
' Test.txt Test2.txt
ID ID2 ID3 Name Telephone Name Telephone
2 C + Sam 013 Henry 013
3 A - Jena 014 Ho 014
1 A + John 011 Jamy 011
1 B - Mike 012 Mark 012
4 B + Peter 015 Jung 015
如果要对输出进行排序,请将输出通过管道传输到| { read header; echo "$header"; sort; }
使用join
,您只能加入一个字段。你不得不求助于
join -j1 -t$'\t' <(sed 's/\t/:/;s/\t/:/' Test.txt|sort) \
<(sed 's/\t/:/;s/\t/:/' Test2.txt|sort) |
sed 's/:/\t/;s/:/\t/'
然后,将标题留在底部(您可以使用| tac | { read header; echo "$header"; tac; }
修复
对评论的回应:
awk -F"\t" '
{key = $1 FS $2 FS $3}
NR == 1 {header = key}
!(key in result) {result[key] = $0; next}
{ for (i=4; i <= NF; i++) result[key] = result[key] FS $i }
END {
print result[header]
delete result[header]
PROCINFO["sorted_in"] = "@ind_str_asc" # if using GNU awk
for (key in result) print result[key]
}
' Test.txt Test2.txt # ... and other files
答案 1 :(得分:1)
使用GNU bash,GNU核心实用程序和GNU awk:
join -j 5 <(sort -n Test.txt) <(sort -n Test2.txt) | awk '{print $2,$3,$4,$5,$1,$9,$1}' | column -t
输出:
ID ID2 ID3 Name Telephone Name Telephone
1 A + John 011 Jamy 011
1 B - Mike 012 Mark 012
2 C + Sam 013 Henry 013
3 A - Jena 014 Ho 014
4 B + Peter 015 Jung 015
答案 2 :(得分:1)
使用awk
,您只需为文件中显示的唯一键构建字符串即可。然后,您可以将输出传输到column -t
以进行漂亮打印。
我已使用第1,2和3列作为键,并将每个文件的剩余列构建到原始行。
awk --re-interval -F"\t" '
{ key = $1 SUBSEP $2 SUBSEP $3 }
{
if (line[key]) {
sub (/([^\t]+\t+){3}/,"");
line[key] = line[key] FS $0
}
else {
line[key] = $0
}
}
END {
for (key in line) print line[key]
}' file* | column -t | sort -r
ID ID2 ID3 Name Telephone Name Telephone
4 B + Peter 015 Jung 015
3 A - Jena 014 Ho 014
2 C + Sam 013 Henry 013
1 B - Mike 012 Mark 012
1 A + John 011 Jamy 011
注意:如果您使用的是GNU awk v4
或更高版本或BSD awk
,则无需指定--re-interval
。
如果您对perl
开放,那么您可以一次性完成:
perl -F"\t" -lane '
$" = "\t";
$key = "@F[0..2]";
push @{ $line{$key} }, @F[3..$#F];
}{
print join "\t", $_, @{ $line{$_} } for grep { $_ =~ /ID/ } sort keys %line;
print join "\t", $_, @{ $line{$_} } for grep { not $_ =~ /ID/ } sort keys %line
' file*