根据bash中的另一个文件替换文件中的条目

时间:2018-01-17 21:44:28

标签: bash awk grep

好的,所以我有两个文件:

file1.txt

object1 4598 -3.32 0 XxXxXx
object2 5987 -1.98 0 XxXxXx
object3 4529 -3.01 1 AbXxXx
object4 6134 -2.81 0 XxXxXx
object5 5912 -2.12 0 XxXxXx
object6 4529 -3.01 1 TeXxXx
object7 4529 -3.01 1 LoXxXx
object8 6915 -2.64 0 XxXxXx
...

file2.txt

object2 5987 -1.98 1 AnXxXx
object4 6134 -2.81 1 ChXxXx
object8 6915 -2.64 1 SnXxXx

对于两个文件中存在的给定对象,唯一的区别在于第4列和第5列。我想使用file1.txt上提供的信息更新file2.txt。我想要的输出是:

object1 4598 -3.32 0 XxXxXx
object2 5987 -1.98 1 AnXxXx
object3 4529 -3.01 1 AbXxXx
object4 6134 -2.81 1 ChXxXx
object5 5912 -2.12 0 XxXxXx
object6 4529 -3.01 1 TeXxXx
object7 4529 -3.01 1 LoXxXx
object8 6915 -2.64 1 SnXxXx

我能够使用for中的bash循环和grep编写解决方案,合并两个文件,grep基于file1的对象名称,然后做tail -1以获得正确的行。 真的丑陋(见下文)并且处理时间太长(file1.txt有4700行),但它确实给了我想要的输出。

#!/bin/bash

for k in $(awk '{print $1}' file1.txt)
  do
     grep -w $k <(cat file1.txt file2.txt | sort) | tail -1 >> updated_file1.txt
  done

请注意,我(危险地)依赖于sort基于字段4对事物进行排序的事实,因为1-3是相同的。我承认这里有很多可能出错......

我想知道是否有人可以帮我找到更快的解决方案,例如,不需要查看整个文件。提前谢谢!

2 个答案:

答案 0 :(得分:4)

awk救援!

$ awk '      {k=$1 FS $2 FS $3}         # set the key
     NR==FNR {a[k]=$0; next}            # cache the first file's rows by key
     k in a  {$0=a[k]}1' file2 file1    # if key from the second file in cache replace

object1 4598 -3.32 0 XxXxXx
object2 5987 -1.98 1 AnXxXx
object3 4529 -3.01 1 AbXxXx
object4 6134 -2.81 1 ChXxXx
object5 5912 -2.12 0 XxXxXx
object6 4529 -3.01 1 TeXxXx
object7 4529 -3.01 1 LoXxXx
object8 6915 -2.64 1 SnXxXx

这假设前三个字段需要匹配,否则将密钥更改为前一个或前两个字段而不更改其余代码。

答案 1 :(得分:1)

有趣的管道

join -a1 -j1 -o 0,1.2,1.3,2.4,2.5,1.4,1.5 <(sort file1.txt) <(sort file2.txt) |
  tr -s '[:blank:]' |
  cut -d' ' -f 1-5