如何加入 tsv 文件,示例:
TSV
c 7 r z
d 6 s w
f 1 f f
b 8 p y
a 9 q x
tsv
a q a
c r ccc
b p bb
0 0 0
d s dddd
在这里,我想按列“加入”它们,where a$1,a$3==b$1,b$2
并显示其余 (a$2,a$4,b$3) :
6 w dddd
9 x a
8 y bb
7 z ccc
问题是:你会如何在 gawk 中做到这一点?
行的顺序不符合要求(在输出中。在输入中,行的顺序未定义,并且在 a.tsv 和 b.tsv 中可以不同 - 就像关系数据库中的行一样,它们没有顺序)。
唯一性说明:最初,我假设“ key={a$1,a$3}
.As的唯一性”格伦·杰克曼注意到 - 不能从原始问题陈述中假设,因为它不允许根据任何键的唯一行 - 谢谢格伦。
答案1
awk '
BEGIN {FS=OFS="\t"}
NR==FNR {a[$1 FS $3] = $2 FS $4; next}
$1 FS $2 in a {print a[$1 FS $2], $3}
' a.tsv b.tsv
由于评论而更新:由于给定的密钥不是唯一的,因此这里有一种从“a.tsv”构建多个条目的技术
awk '
BEGIN {FS=OFS="\t"}
NR==FNR {
key = $1 FS $3
if (key in a)
a[key] = a[key] "\n" $2 FS $4
else
a[key] = $2 FS $4
next
}
$1 FS $2 in a {
split(a[$1 FS $2], ary, /\n/)
for (idx in ary)
print ary[idx], $3
}
' a.tsv b.tsv
答案2
我将任务分成两个不同的程序:
使用加入(1)连接两个文件
awk(1)或者切割(1)去除不需要的列
答案3
我不太清楚awk
,但它是专门为处理文本文件中的字段而设计的,所以我认为它可以很好地完成这项工作,但因为你似乎(?)表达了对join
(在ktf的评论),这里是一个使用标准 unix 工具的解决方案:join
and cut
and paste
and sort
-- 很多“and”,但它有效并且可以作为为什么awk
更好的一个例子:)...我把它主要是为了然后是方法比较因素。
join -t $'\t' -o 1.2 1.3 2.2 \
<(paste <(paste <(cut -f1 a.tsv) \
<(cut -f3 a.tsv) \
| tr '\t' '\0' ) \
<(cut -f2 a.tsv) \
<(cut -f4 a.tsv) \
| sort ) \
<(paste <(paste <(cut -f1 b.tsv) \
<(cut -f2 b.tsv) \
| tr '\t' '\0' ) \
<(cut -f3 b.tsv) \
| sort )
答案4
最后我成功做到了。所以我分享我的解决方案:
awk '
BEGIN {
FS=OFS="\t"
while ((getline < "a.tsv") > 0){
a2[$1,$3] = $2; a4[$1,$3] = $4
}
}
($1,$2) in a2 { print a2[$1,$2] FS a4[$1,$2] FS $3 }' < b.tsv
产生:
9 x a
7 z ccc
8 y bb
6 w dddd
这个解决方案:
- 不假设输入行的顺序
- 当某些行在其他文件中没有匹配时有效
- 假设中的行
a.tsv
是唯一的key = {a$1,a$3}
对于那些感兴趣的人右连接,你只需要删除if( ($1,$2) in a2)
语句即可。对于那些感兴趣的人左连接,只需执行“右连接”版本并将 a.tsv 与 b.tsv 交换(并相应地更改代码)。
唯一性说明: 作为格伦·杰克曼注意到,a.tsv
根据 ,该行可能不是唯一的key={a$1,a$3}
,您可能想查看他的解决方案。