如何使用 AWK 合并两个文件? [复制]

Posted

技术标签:

【中文标题】如何使用 AWK 合并两个文件? [复制]【英文标题】:How to merge two files using AWK? [duplicate] 【发布时间】:2011-07-24 23:20:27 【问题描述】:

文件 1 有 5 个字段 A B C D E,其中字段 A 是一个整数值

文件 2 有 3 个字段 A F G

文件1的行数比文件2大很多(20^6到5000)

文件1中A的所有条目都出现在文件2中的字段A中

我喜欢按字段A合并两个文件并携带F和G

期望的输出是 A B C D E F G

例子

文件 1

 A     B     C    D    E
4050 S00001 31228 3286 0
4050 S00012 31227 4251 0
4049 S00001 28342 3021 1
4048 S00001 46578 4210 0
4048 S00113 31221 4250 0
4047 S00122 31225 4249 0
4046 S00344 31322 4000 1

文件 2

A     F    G   
4050 12.1 23.6
4049 14.4 47.8   
4048 23.2 43.9
4047 45.5 21.6

期望的输出

A    B      C      D   E F    G
4050 S00001 31228 3286 0 12.1 23.6
4050 S00012 31227 4251 0 12.1 23.6
4049 S00001 28342 3021 1 14.4 47.8
4048 S00001 46578 4210 0 23.2 43.9
4048 S00113 31221 4250 0 23.2 43.9
4047 S00122 31225 4249 0 45.5 21.6

【问题讨论】:

您是故意遗漏了文件 2 中以 4046 开头的行还是意外遗漏?这很重要,因为您想要的输出没有显示 4046 行,但之前您说文件 1 的所有行都包含在文件 2 中。 @SiegeX。抱歉,这是一个意外遗漏。 在三元组中,我认为这个例子是最好的。 【参考方案1】:

您需要将文件 2 中的条目读入 BEGIN 块中的一对关联数组中。假设 GNU Awk:

BEGIN  while (getline < "File 2")  f[$1] = $2; g[$1] = $3  

在主处理块中,您从文件 1 中读取该行并使用在 BEGIN 块中创建的数组中的正确数据打印它:

 print $0, f[$1], g[$1] 

将文件 1 作为文件名参数提供给程序。

awk 'BEGIN  while (getline < "File 2")  f[$1] = $2; g[$1] = $3  
     print $0, f[$1], g[$1] ' "File 1"

由于文件名中有空格,因此需要在文件名参数周围加上引号。您需要在 getline 文件名周围加上引号,即使它不包含空格,否则它将是一个变量名。

【讨论】:

【参考方案2】:

谢天谢地,你根本不需要写这个。 Unix 有一个 join 命令可以为您执行此操作。

join -1 1 -2 1 File1 File2

这里是“在行动”:

will-hartungs-computer:tmp will$ cat f1
4050 S00001 31228 3286 0
4050 S00012 31227 4251 0
4049 S00001 28342 3021 1
4048 S00001 46578 4210 0
4048 S00113 31221 4250 0
4047 S00122 31225 4249 0
4046 S00344 31322 4000 1
will-hartungs-computer:tmp will$ cat f2
4050 12.1 23.6
4049 14.4 47.8   
4048 23.2 43.9
4047 45.5 21.6
will-hartungs-computer:tmp will$ join -1 1 -2 1 f1 f2
4050 S00001 31228 3286 0 12.1 23.6
4050 S00012 31227 4251 0 12.1 23.6
4049 S00001 28342 3021 1 14.4 47.8
4048 S00001 46578 4210 0 23.2 43.9
4048 S00113 31221 4250 0 23.2 43.9
4047 S00122 31225 4249 0 45.5 21.6
will-hartungs-computer:tmp will$ 

【讨论】:

使用join 要求文件按顺序排列;显示的输入未按排序顺序(或未按升序排序)。这可能是使用awk 的练习,所以很可能您的其他明智(一旦更正)解决方案是不可接受的。 @Will。哇。 join 命令是否要求两个文件的行数相同?谢谢 @Jonathan 好吧,至少在我的 Mac 上,join 命令完全符合他的要求,而且文件没有排序,我只是将它们剪切/粘贴到 vi 中。 @Tony 不,文件(显然)不必具有相同的行数。 是的,当它们出现故障时似乎有问题。它似乎不喜欢第二个文件中不在第一个文件中的项目。当然,如果顺序不重要,还有 sort(1)。【参考方案3】:
$ awk 'FNR==NRa[$1]=$2 FS $3;next print $0, a[$1]' file2 file1
4050 S00001 31228 3286 0 12.1 23.6
4050 S00012 31227 4251 0 12.1 23.6
4049 S00001 28342 3021 1 14.4 47.8
4048 S00001 46578 4210 0 23.2 43.9
4048 S00113 31221 4250 0 23.2 43.9
4047 S00122 31225 4249 0 45.5 21.6
4046 S00344 31322 4000 1

解释:(部分基于另一个question。不过有点晚了。)

FNR指的是当前文件中的记录号(通常是行号),NR指的是总记录号。运算符 == 是一个比较运算符,当两个周围的操作数相等时返回 true。所以FNR==NRcommands 表示括号内的命令只在处理第一个文件时执行(file2 现在)。

FS 指的是字段分隔符,$1$2 等是一行中的第一个、第二个等字段。 a[$1]=$2 FS $3 表示字典(/array)(名为a)填充有$1 键和$2 FS $3 值。

; 分隔命令

next 表示当前行忽略任何其他命令。 (处理在下一行继续。)

$0 是整行

print $0, a[$1] 简单地打印出整行和a[$1] 的值(如果$1 在字典中,否则只打印$0)。现在它只对第二个文件(file1 now)执行,因为FNR==NR...;next

【讨论】:

@kurumi 没有合并,只打印了文件 1 @tony,不,我测试过了。查看我的编辑 @kurumi 在看到你的答案之前,我想出了几乎相同的答案,但最好对那些最先到达那里的人进行投票而不是复制。因此,在我删除我的并为你投票之前,你应该编辑你的,在我的回答中添加 (a[$1]) 部分。 你能详细说明a[$1]=$2吗?你是怎么拿到 2 美元的? 一点解释也无妨。【参考方案4】:
awk 'BEGINOFS=","  FNR==NR F[$1]=$2;G[$1]=$3;next print $1,$2,$3,$4,$5,F[$1],G[$1]' file2.txt file1.txt

【讨论】:

这个答案出现在低质量审查队列中,大概是因为您没有提供任何代码解释。如果此代码回答了问题,请考虑在答案中添加一些解释代码的文本。这样一来,您就更有可能获得更多支持,并帮助提问者学习新知识。 您能稍微解释一下吗?真的很感激。

以上是关于如何使用 AWK 合并两个文件? [复制]的主要内容,如果未能解决你的问题,请参考以下文章

如何轻松合并两个源文件?

如何合并两个文本文件?

如何使用 awk 重新格式化 JSON? [复制]

按一列合并两个文件 AWK

如何使用 grep 或 awk 打印出特定的块? [复制]

如何在响应中将两个变量合并为一个? [复制]