我知道这个问题已经被问过几次了。这是一个示例:
Using AWK to merge two files based on multiple columns
如果发生以下匹配,我的目标是打印出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[$2 FS $6 FS $7]=$17 FS $18;next} {if($2 FS $4 FS $5 in key); print $2 FS $4 FS $5 FS $7 FS key[$2 FS $6 FS $7]}' 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个。
答案 0 :(得分:1)
请尝试以下操作(GNU sed):
awk 'BEGIN{RS="\r\n";FS=OFS=",";SUBSEP=FS}NR==FNR{arr[$2,$6,$7]=$17 FS $18;next} {if(arr[$2,$4,$5]) print $2,$4,$5,$7,arr[$2,$4,$5]}'
这是BEGIN
块踢入的时间。OFS
也踢入踢的时间。
当我们打印出许多由相同内容分隔开的字段时,我们可以设置OFS
,并在要打印的内容之间放入逗号。
在为数组中的键分配值时,无需检查key in arr
,
默认情况下,如果之前未分配arr[somekey]
,则其为empty
/ ""
,并且其awk的值为false
(在标量上下文中为0
),并且非空字符串的计算结果为true
(true
中没有字面上的false
和awk
)。
(您使用了错误的array
名称,$2,$6,$7
是此处数组arr
中的键。使用key
作为数组名称会造成混淆。)
您可以测试一些简单的概念,例如:
awk 'BEGIN{print arr["newkey"]}'
您不需要输入文件即可执行BEGIN
块。
此外,有时可以使用引号,以避免造成混淆和潜在的问题。
更新:
您的文件实际上以\n
结尾,如果您不确定行的结尾是什么,请使用以下命令:
awk 'BEGIN{RS="\r\n|\n|\r";FS=OFS=",";SUBSEP=FS}NR==FNR{arr[$2,$6,$7]=$17 FS $18;next} {if(arr[$2,$4,$5]) print $2,$4,$5,$7,arr[$2,$4,$5]}' file_a.csv file_b.csv
或这个(这个将忽略空行):
awk 'BEGIN{RS="[\r\n]+";FS=OFS=",";SUBSEP=FS}NR==FNR{arr[$2,$6,$7]=$17 FS $18;next} {if(arr[$2,$4,$5]) print $2,$4,$5,$7,arr[$2,$4,$5]}' file_a.csv file_b.csv
也,最好通过以下方式先进行转换以避免这种情况:
sed -i 's/\r//' files
或者您可以使用dos2unix
命令:
dos2unix file
这是一个方便的命令行工具,只能做上述事情。
如果您的系统中还没有它,可以安装它。
转换后,通常情况下无需分配RS
。
答案 1 :(得分:0)
$ awk 'BEGIN {RS="\r\n"; FS=OFS=","}
NR==FNR {a[$2,$6,$7]=$17 OFS $18; next}
($2,$4,$5) in a {print $2,$4,$5,$7,a[$2,$4,$5]}' file1 file2 > output
您的主要问题是,在数组查找中,您应使用的索引是第二个文件密钥,而不是第一个文件密钥。 if条件之后的分号也是错误的。剩下的只是化妆品。
不确定是否要终止输出\r\n
,如果也设置ORS=RS
,则仅终止于换行符。
答案 2 :(得分:0)
由于您已经提到该文件很大,因此可以尝试使用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
$