用awk合并两个文件


9

File1.txt

item1   carA
item2   carB
item3   carC
item4   platD
item5   carE

File2.txt

carA  platA
carB  platB
carC  platC
carE  platE

想要的输出:

item1   platA
item2   platB
item3   platC
item4   platD
item5   platE

我该怎么做?

Answers:


11

以下答案基于SO中类似的问答,并进行了一些相关的修改:

$ awk 'FNR==NR {dict[$1]=$2; next} {$2=($2 in dict) ? dict[$2] : $2}1' file2.txt file1.txt 
item1 platA
item2 platB
item3 platC
item4 platD
item5 platE

这个想法是用索引创建一个哈希映射,并将其用作字典。

对于您在评论中提出的第二个问题(如果第二列file1.txt是第六列,应该更改什么):

如果输入文件如下file1b.txt

item1 A5 B C D carA
item2 A4 1 2 3 carB
item3 A3 2 3 4 carC
item4 A2 4 5 6 platD
item5 A1 7 8 9 carE

以下命令将执行此操作:

$ awk 'FNR==NR {dict[$1]=$2; next} {$2=($6 in dict) ? dict[$6] : $6;$3="";$4="";$5="";$6=""}1' file2.txt file1b.txt 
item1 platA    
item2 platB    
item3 platC    
item4 platD    
item5 platE    

1
@pawana-我已经更新了答案,也可以解决您的第二个问题。如果我已经回答了您的问题,请接受
Yaron

6

我知道您说过awk,但是有一个join用于此目的的命令...

{
  join -o 1.1,2.2 -1 2 -2 1 <(sort -k 2 File1.txt) <(sort -k 1 File2.txt)     
  join -v 1 -o 1.1,1.2 -1 2 -2 1 <(sort -k 2 File1.txt) <(sort -k 1 File2.txt) 
} | sort -k 1

join如果不是此行,那么使用第一个命令就足够了:

item4   platD

该命令基本上说:基于第一个文件的第二列(-1 2)和第二个文件的第一列(-2 1)进行联接,并输出第一个文件的第一列和第二个文件的第二列(-o 1.1,2.2)。那只显示配对的线。第二个join命令几乎说了同样的话,但是它表示要显示第一个文件中无法配对的行(-v 1),并输出第一个文件的第一列和第一个文件的第二列(-o 1.1,1.2)。然后,我们将两者的输出排序。sort -k 1表示根据第一列sort -k 2进行排序,并且表示根据第二列进行排序。在将文件传递给之前,根据连接列对文件进行排序很重要join

现在,我写了两次排序,因为如果可以的话,我不喜欢在目录中放一些文件。但是,就像David Foerster所说的那样,根据文件的大小,您可能希望对文件进行排序并首先保存它们,而不必等待对每个文件进行两次排序。为了给出大小的概念,下面是在计算机上对100万和1000万行进行排序的时间:

$ ruby -e '(1..1000000).each {|i| puts "item#{i}   plat#{i}"}' | shuf > 1million.txt 
$ ruby -e '(1..10000000).each {|i| puts "item#{i}   plat#{i}"}' | shuf > 10million.txt 
$ head 10million.txt 
item530284   plat530284
item7946579   plat7946579
item1521735   plat1521735
item9762844   plat9762844
item2289811   plat2289811
item6878181   plat6878181
item7957075   plat7957075
item2527811   plat2527811
item5940907   plat5940907
item3289494   plat3289494
$ TIMEFORMAT=%E
$ time sort 1million.txt >/dev/null
1.547
$ time sort 10million.txt >/dev/null
19.187

一百万条线路是1.5秒,一千万条线路是19秒。


在这种情况下,最好将排序后的输入数据存储在(临时)中间文件中,因为对于非平凡大小的数据集,排序会花费很长时间。否则+1。
David Foerster '18

@David这是一个好点。就个人而言,我真的不喜欢必须创建中间文件,但是我也对长时间运行的进程不耐烦。我想知道“平凡的大小”是什么,所以我做了一个小的基准,并将其与您的建议一起添加到了答案中。
JoL

在相当现代的台式计算机上,对1个mio记录进行排序足够快。随着2个3个数量级的增加,更多的事情开始变得有趣起来。在任何情况下,过去的(真实)时间(%E时间格式)对于衡量计算性能都不太有趣。用户模式的CPU时间(%U或只是一个未设置的TIMEFORMAT变量)将更加有意义。
David Foerster '18

@David我对不同时期的用例不是很熟悉。为什么它更有趣?经过的时间与我实际等待的时间一致。对于1.5秒的命令,我得到4.5秒%U
JoL

1
经过的时间受等待在同一系统上运行的其他任务并阻止I / O请求所花费的时间影响。(用户)CPU时间不正确。通常,在比较计算绑定算法的速度时,人们希望忽略I / O,避免由于其他后台任务而导致测量错误。重要的问题是“该算法需要对该数据集进行多少计算?” 而不是“我的计算机在等待该计算完成时花了所有时间?”
David Foerster,
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.