如何使用 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 合并两个文件? [复制]的主要内容,如果未能解决你的问题,请参考以下文章