Linux 使用Bash在多个字段上使用非相等键连接匹配的列?
我知道以前也有人问过类似的问题,但我似乎找不到解决具体问题的办法 我的文件结构如下(col1=ID,col2=time increment,col3=data): 我的目标是根据ID第一次和时间第二次连接这两个文件。但是,还必须添加不相等的时间值,并且数据列(col3)必须放置在输出文件的正确列中 期望输出:Linux 使用Bash在多个字段上使用非相等键连接匹配的列?,linux,bash,join,awk,Linux,Bash,Join,Awk,我知道以前也有人问过类似的问题,但我似乎找不到解决具体问题的办法 我的文件结构如下(col1=ID,col2=time increment,col3=data): 我的目标是根据ID第一次和时间第二次连接这两个文件。但是,还必须添加不相等的时间值,并且数据列(col3)必须放置在输出文件的正确列中 期望输出: 14.000119 0 yes no 14.000119 69 yes 14.000119 70 no 14.000
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的第四列)。使用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
join-j1-a1-a2-e'-o'0,1.4,2.4'-t$'\t'
使用GNU awk表示数组的数组,并将其排序为:
$ 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
使用awk
和sort
的一点帮助,如何:
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
你能接受这个答案吗(是的,你自己的答案),这样问题的答案就更清楚了。是的,但是有两天的等待期。如果您的真实数据中可以有多个ID,并且包含了给定ID仅出现在文件1中或仅出现在文件2中的情况,那么您应该在示例中提供多个ID。永远不要给变量命名\uu
顺便说一句-理解变量代表什么比给它命名一个字母更没用!在实际文件中,变量显然没有命名为u,并且具有更多或更少的ID不会导致问题的性质,因为数据无论如何都是在第一列上排序的。谢谢你的回答;这一点也不明显。为什么要将一个变量从有意义的名称重命名为\uuu
,以便在一个问题中发布,您希望使您的脚本尽可能容易让其他人理解,以便他们能够帮助您?拥有更多的ID与拥有1个ID的问题大不相同,您可能希望以各种方式处理仅出现在1个文件中的ID。例如,在我的回答中,我假设您希望两个文件中的所有ID都以数字顺序显示,但您可能希望忽略一些ID,或者希望一个文件特有的ID显示在开始或结束或其他位置。很好,表示问题已解决的方法是单击复选标记接受答案。(但现在我看到你答案上的评论,你知道这一点。)请不要在你的问题中编辑“已解决”。请不要添加编辑/更新,只需编辑并尽可能地发布文章即可。
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