基于几列比较 csv 中的 2 个文件,并使用 shell 将第一个文件中的一列替换为第二个文件中另一列的匹配值

基于几列比较 csv 中的 2 个文件,并使用 shell 将第一个文件中的一列替换为第二个文件中另一列的匹配值

我有一个关于根据不按顺序的相应列比较两个文件的问题。

文件1

AAAA,BBBB,CCCC,DDDD,EEEE,FFFF,GGGG,HHHH (header)
a,b,c,d,e,f,g,h
aa,bb,cc,dd,ee,ff,gg,hh
aaa,bbb,ccc,ddd,eee,fff,ggg,hhh

文件2

GGGG,AAAA,CCCC,DDDD,HHHH,EEEE,BBBB,FFFF,IIII (header)
g,a,c,d,h,e,b,f,i
gg,aa,cc,dd,hh,ee,bb,ff,ii

在上面的示例中,我必须将文件 1 中的 4 个不同列与文件 2 中的 4 列进行比较,如果找到匹配项,请使用添加的列更新文件 2 并表示已匹配,并且不要再次使用该行进行比较并替换上的列文件 1 中包含文件 2 中的列

比较文件 1 和文件 2 中从 a 到 h 的 6 列,如果找到匹配,则将 a 列替换为 i 列

最终文件应该是文件3

AAAA,BBBB,CCCC,DDDD,EEEE,FFFF,GGGG,HHHH
i,b,c,d,e,f,g,h
ii,bb,cc,dd,ee,ff,gg,hh

答案1

使用磨坊主( mlr) 对两个文件共有的命名字段执行关系 JOIN 操作:

$ mlr --csv join -j AAAA,BBBB,CCCC,DDDD,EEEE,FFFF,GGGG,HHHH -f file1.csv file2.csv
AAAA,BBBB,CCCC,DDDD,EEEE,FFFF,GGGG,HHHH,IIII
a,b,c,d,e,f,g,h,i
aa,bb,cc,dd,ee,ff,gg,hh,ii

AAAA然后,为了用 的内容替换该列的内容,IIII我们可以将该IIII列移动到开头,同时删除该AAAA列(这是通过 Millercut操作完成的),然后重新标记IIIIAAAA(这是通过 Millerlabel操作完成的):

mlr --csv \
    join -j AAAA,BBBB,CCCC,DDDD,EEEE,FFFF,GGGG,HHHH -f file1.csv then \
    cut -o -f IIII,BBBB,CCCC,DDDD,EEEE,FFFF,GGGG,HHHH then \
    label AAAA file2.csv

cut操作可以分为两个单独的步骤;一个排除该AAAA字段,另一个对剩余字段重新排序,使其IIII成为第一个字段。这将使我们能够避免长长的字段列表:

mlr --csv \
    join -j AAAA,BBBB,CCCC,DDDD,EEEE,FFFF,GGGG,HHHH -f file1.csv then \
    cut -x -f AAAA then \
    reorder -f IIII then \
    label AAAA file2.csv

最终输出:

AAAA,BBBB,CCCC,DDDD,EEEE,FFFF,GGGG,HHHH
i,b,c,d,e,f,g,h
ii,bb,cc,dd,ee,ff,gg,hh

相关内容