使用 Bash 在文件之间连接多个字段上具有不相等键的匹配列?



我知道以前有人问过类似的问题(例如,在Unix上连接文本文件中的多个字段(,但我似乎找不到解决我特定问题的方法。

我的文件结构如下(col1=ID,col2=时间增量,col3=数据(:

head file1
14.000119    0       yes
14.000119    69      yes
14.000119    168     no
14.000119    259
14.000119    431
14.000119    888     yes
head file2
14.000119    0       no
14.000119    70      no
14.000119    169     yes
14.000119    262
14.000119    456
14.000119    525

我的目标是首先根据 ID 和时间第二连接这两个文件。但是,还必须添加不相等的时间值,并且数据列 (col3( 必须放在输出文件中的正确列中。

期望输出:

14.000119    0      yes    no    
14.000119    69     yes
14.000119    70            no
14.000119    168    no    
14.000119    169           yes
14.000119    259
14.000119    262
14.000119    431
14.000119    456
14.000119    525
14.000119    888    yes

列按制表符分隔。我知道有一个awk或join的解决方案,但我似乎不能正确。我最接近的是使用

awk -F\t '{
o1=$1;o2=$2
$1=$2="";gsub("t","")
_[o1 FS o2]=_[o1 FS o2] FS $0
} END {
for(i in _) print i,_[i]
}' file1 file2 | sort -k1,1 -k2,2 -n

这给了我:

14.000119       0         yes      no
14.000119       69        yes
14.000119       70        no
14.000119       168       no
14.000119       169       yes
14.000119       259
14.000119       262
14.000119       431
14.000119       456
14.000119       525
14.000119       888       yes

但如您所见,如果 file1 中同一键的值不为空,则数据值仅在正确的列中填充(file2 为 4th(。

使用join和一些解决方法解决了它!

join -j1 -a 1 -a 2 -e '' -o '0,1.4,2.4' -t $'t' 
<(<file1 awk -F\t '{print $1"-"$2 "t" $0}' | sort -k1,1) 
<(<file2 awk -F\t '{print $1"-"$2 "t" $0}' | sort -k1,1) 
| sed 's/-/t/g' | sort -k1,1 -k2,2 -n

说明:
-j1: 连接第一个字段
-a 1 -a 2:还打印两个文件中不可配对的行
-e '':用空字段填充空白-o 0,1.4,2.4
输出文件1和文件2的第一个字段以及第4个字段-t $'t':制表符
分隔<(<file1 ...)打印
前两列,中间有"-"而不是制表符, 将前两列"压缩"为一列(连接仅适用于列(
sed 's/-/t/g':将破折号恢复为选项卡
sort -k1,1 -k2,2 -n:现在输出再次包含 4 列,按第一列和第二列排序

使用 GNU awk 表示数组的数组和sorted_in:

$ cat tst.awk
BEGIN { FS=OFS="t" }
{ vals[$1][$2][ARGIND] = $3 }
END {
PROCINFO["sorted_in"] = "@ind_num_asc"
for (id in vals) {
for (time in vals[id]) {
print id, time, vals[id][time][1], vals[id][time][2]
}
}
}
$ awk -f tst.awk file1 file2
14.000119       0       yes     no
14.000119       69      yes
14.000119       70              no
14.000119       168     no
14.000119       169             yes
14.000119       259
14.000119       262
14.000119       431
14.000119       456
14.000119       525
14.000119       888     yes

有了awksort的一点帮助,怎么样:

awk -F't' '
NR==FNR {a[$1"t"$2] = $3; next}
{a[$1"t"$2] ? a[$1"t"$2] = a[$1"t"$2]"t"$3 : a[$1"t"$2] = "t"$3}
END {for (i in a) print i"t"a[i]}
' file1 file2 | sort -k1,1n -k2,2n

结果:

14.000119       0       yes     no
14.000119       69      yes
14.000119       70              no
14.000119       168     no
14.000119       169             yes
14.000119       259
14.000119       262
14.000119       431
14.000119       456
14.000119       525
14.000119       888     yes

最新更新