使用AWK根据多个条件合并两个文件

Using AWK to merge two files based on multiple conditions

我知道这个问题已经被问过好几次了。这是一个例子:

我的目标是打印出 file_b 的第 2、4、5 和 7 列以及 file_a 的第 17 和 18 列,如果发生以下匹配: file_a.csv 的第 2、6 和 7 列分别与 file_b.csv 的第 2、4 和 5 列匹配。

但无论我怎么努力,我都无法让它适用于我的情况。这是我的两个文件:

file_a.csv

col2, col6, col7, col17, col18
a, b, c, 145, 88
e, f, g, 101, 96
x, y, z, 243, 222

file_b.csv

col2, col4, col5, col7
a, b, c, 4.5
e, f, g, 6.3
x, k, l, 12.9

输出应如下所示:

col2, col4, col5, col7, col17, col18
a, b, c, 4.5, 145, 88
e, f, g, 6.3, 101, 96

我试过这个:

awk -F, -v RS='\r\n' 'NR==FNR{key[ FS  FS ]= FS ;next} {if( FS  FS  in key); print  FS  FS  FS  FS key[ FS  FS ]}' file_a.csv file_b.csv > out.csv

目前我得到的输出是:

col2, col4, col5, col7,
a, b, c, 4.5,
e, f, g, 6.3,

换句话说,file_a 的 col17 和 col18 没有出现。

昨天我问了一个相关问题,我遇到了换行符问题。这个问题得到了回答和解决,但现在我认为这个问题与检查 if 条件有关。

更新: 我正在共享指向实际数据的截断副本的链接。这些文件与实际文件之间的唯一区别是真实文件有数百万行。这些只有 10 个。

file_a.csv

file_b.csv

请试试这个 (GNU sed):

awk 'BEGIN{RS="\r\n";FS=OFS=",";SUBSEP=FS}NR==FNR{arr[,,]= FS ;next} {if(arr[,,]) print ,,,,arr[,,]}'

这是 BEGIN 块开始的时间。同时 OFS 开始。
当我们要打印出很多由同一个东西分隔的字段时,我们可以设置OFS,并简单地在我们要打印的东西之间加上逗号。

为数组中的键赋值后,无需检查 key in arr
默认情况下,当之前未分配 arr[somekey] 时,它是 empty/"",并且它在 awk 中计算为 false(在标量上下文中为 0),并且非空字符串的计算结果为 trueawk 中没有字面上的 truefalse)。
(你使用了错误的array名称,,,是数组arr中的键。使用key作为数组名称会造成混淆。)

您可以像这样测试一些简单的概念:

awk 'BEGIN{print arr["newkey"]}'

您不需要输入文件来执行 BEGIN 块。

此外,有时您可以使用引号,以避免混淆和潜在问题。

更新: 您的文件实际上以 \n 结尾,如果您不能确定行结尾是什么,请使用:

awk 'BEGIN{RS="\r\n|\n|\r";FS=OFS=",";SUBSEP=FS}NR==FNR{arr[,,]= FS ;next} {if(arr[,,]) print ,,,,arr[,,]}' file_a.csv file_b.csv

或者这个(这个会忽略空行):

awk 'BEGIN{RS="[\r\n]+";FS=OFS=",";SUBSEP=FS}NR==FNR{arr[,,]= FS ;next} {if(arr[,,]) print ,,,,arr[,,]}' file_a.csv file_b.csv

还有,最好先转换,避免这种情况,by:

sed -i 's/\r//' files

或者你可以使用dos2unix命令:

dos2unix file

这是一个方便的命令行工具,只做上面的事情。
如果您的系统中没有它,您可以安装它。
转换后,一般情况下不需要赋值RS

$ awk 'BEGIN      {RS="\r\n"; FS=OFS=","}
       NR==FNR    {a[,,]= OFS ; next} 
  (,,) in a {print ,,,,a[,,]}' file1 file2 > output

您的主要问题是,在数组查找中,您应该使用的索引是第二个文件键,而不是第一个文件键。 if 条件后的分号也是错误的。其余的只是化妆品。

不确定您是否希望输出 \r\n 终止,如果是这样也设置 ORS=RS,否则它只是换行符。

既然你提到文件很大,你可以尝试一下 Perl,如果可以的话。

假设文件有“\r”。

$ cat file_a.csv
col2, col6, col7, col17, col18
a, b, c, 145, 88
e, f, g, 101, 96
x, y, z, 243, 222
$ cat file_b.csv
col2, col4, col5, col7
a, b, c, 4.5
e, f, g, 6.3
x, k, l, 12.9
$ perl -F, -lane 'BEGIN { %kv=map{chomp;chop;@a=split(",");"$a[0],$a[1],$a[2]"=>"$a[3]"} qx(cat file_b.csv) } if($.>1){ $x="$F[0],$F[1],$F[2]";chomp($F[-1]);print "$x,$kv{$x}",join(",",@F[-2,-1]) if $kv{$x} } ' file_a.csv
a, b, c, 4.5 145, 88
e, f, g, 6.3 101, 96
$