【问题标题】:AWK in shell script - How to compare and merge TWO files based on a shared key (2 common fields)?shell 脚本中的 AWK - 如何基于共享密钥(2 个公共字段)比较和合并两个文件?
【发布时间】:2012-08-23 18:04:46
【问题描述】:

请有人帮忙比较两个文件, 我使用了以下命令,但我无法成功,

awk -F, 'NR == FNR {a[$1,$2]; next} (($1,$2) in a )' temp1.dat temp2.​​dat

这是我的需要, 需要比较以下两个 dat 文件中的前两个字段,并将结果按预期合并到 file3 中(第一个字段,第二个字段,temp1.dat 的 3 个字段,temp2.​​dat 的 3 个字段)

文件1:temp1.dat

A, AB,100
B,BB,200
C,CC,300

文件2:temp2.​​dat

A,AB,10
C,CC,30
D,DF, 4

文件3:输出

A, AB,100,10
C,CC,300,30

【问题讨论】:

  • 为什么不只是diff file1 file2
  • 我只需要 file3 匹配列 H2CO3。
  • 使用join命令。
  • 对于未来的读者和@AmitNaidu——join 命令是不够的,因为条件规定两列必须匹配。当然,sed 可以首先用于组合键列,然后,在对新组合键列上的每个文件进行排序之后,join 就足够了(最终的sed 过滤器可以再次分离连接的列)。对于较大的文件,也许 join 会更有效,尤其是当它们已经在两列上排序时。

标签: shell unix awk ksh


【解决方案1】:

试试:

awk -F, '{i=$1 SUBSEP $2} NR==FNR{A[i]=$3; next} i in A{print $0,A[i]}' file2 file1

【讨论】:

  • +1 更好的答案。只需要 OFS 或逗号。像这样减少对 $ 变量的引用也可以提高性能。
【解决方案2】:

awk -F, 'BEGIN{OFS=","}FNR==NR{a[$1$2]=$3;next}($1$2 in a && $3=$3","a[$1$2])' file2 file1

测试如下:

> cat file1
A,AB,100
B,BB,200
C,CC,300
> cat file2
A,AB,10
C,CC,30
D,DF,4
> awk -F, 'BEGIN{OFS=","}FNR==NR{a[$1$2]=$3;next}($1$2 in a && $3=$3","a[$1$2])' file2 file1
A,AB,100,10
C,CC,300,30
> 
  • FNR==NR{a[$1$2]=$3;next}应用于第一个文件file2
  • 它说直到FNR==NR 执行代码块。
  • FNR=当前文件的行号
  • NR= 两个文件总行数。
  • 所以在上述语句之后,一个关联数组的索引为$1$2,值为$3
  • 现在($1$2 in a && $3=$3","a[$1$2]) 这对FNR!=NR执行。其中检查索引$1$2是否作为数组中的索引存在,然后第二个条件是将file1的第三个字段更改为$3=$3","a[$1$2]所以现在$0包含公共($1$2 ) 行更改了其中的第三个字段。

也必须为四个文件编写类似的逻辑。

【讨论】:

  • sarathi 非常感谢,它对我来说工作得很好,你能解释一下你在这里使用的逻辑吗,是否可以将相同的比较逻辑应用于四个文件。
  • 这是非常不习惯的。 ($1$2 in a && $3=$3","a[$1$2]) 写的话会更清楚$1$2 in a { $3=$3","a[$1$2]; print }
  • 最好在索引中的字段之间使用分隔符。否则,如果字段的长度不同,则一个字段的一部分可能会“模糊”到另一个字段中,从而导致不可预测的结果。通常人们会为此使用SUBSEP..
  • 或者只是$1$2 in a { print $3, a[$1$2] },因为已经设置了OFS。不需要聪明或混淆。根据需要更改数据文件的顺序。
猜你喜欢
  • 1970-01-01
  • 2016-01-16
  • 1970-01-01
  • 1970-01-01
  • 2022-01-22
  • 1970-01-01
  • 2014-07-12
  • 2012-10-18
  • 1970-01-01
相关资源
最近更新 更多