繁体   English   中英

条件Awk hashmap匹配查找

[英]Conditional Awk hashmap match lookup

我有2个表格文件。 一个文件包含50个键值的映射,仅称为lookup_file.txt。 另一个文件具有30列和数百万行的实际表格数据。 data.txt我想用lookup_file.txt中的值替换第二个文件的id列

我怎样才能做到这一点? 我更喜欢在bash脚本中使用awk ..此外,是否有一个hashmap数据结构我可以在bash中用于存储50个键/值而不是另一个文件?

假设您的文件有逗号分隔的字段,“id列”是字段3:

awk '
BEGIN{ FS=OFS="," }
NR==FNR { map[$1] = $2; next }
{ $3 = map[$3]; print }
' lookup_file.txt data.txt

如果这些假设中的任何一个是错误的,请告诉我们如果修复不明显......

编辑:如果你想避免(恕我直言可以忽略不计)NR == FNR测试性能影响,这将是使用getline时适用的每种罕见情况之一:

awk '
BEGIN{
   FS=OFS=","
   while ( (getline line < "lookup_file.txt") > 0 ) {
      split(line,f)
      map[f[1]] = f[2]
   }
}
{ $3 = map[$3]; print }
' data.txt

您可以通过bash混合使用“sort”和“join”,而不必将其写入awk / sed,它可能更快:

key.cvs(id,name)

1,homer
2,marge
3,bart
4,lisa
5,maggie

data.cvs(姓名,动物,所有者,年龄)

snowball,dog,3,1
frosty,yeti,1,245
cujo,dog,5,4

现在,您需要首先在用户ID列上对这两个文件进行排序:

cat key.cvs | sort -t, -k1,1 > sorted_keys.cvs
cat data.cvs | sort -t, -k3,3 > sorted_data.cvs

现在加入2个文件:

join -1 1 -2 3 -o "2.1 2.2 1.2 2.4" -t , sorted_keys.cvs sorted_data.cvs > replaced_data.cvs

这应该产生:

snowball,dog,bart,1
frosty,yeti,homer,245
cujo,dog,maggie,4

这个:

-o "2.1 2.2 1.2 2.4"

在最终输出中说出你想要的2个文件中的哪些列。

与其他脚本语言相比,查找和替换多个数据的速度非常快。 我还没有直接与SED / AWK进行比较,但编写一个包装它的bash脚本比写入SED / AWK(至少对我来说)要容易得多。

此外,您可以使用gnu coreutils的升级版本加快排序速度,以便您可以并行执行排序

cat data.cvs | sort --parallel=4 -t, -k3,3 > sorted_data.cvs

4是你要运行它的线程数。我建议每个机器核心2个线程通常会最大化机器,但如果它专用于此,那很好。

有几种方法可以做到这一点。 但是如果你想要一个简单的一个衬垫,没有太多的验证方式,我会选择awk / sed解决方案。

假设如下:

  1. 文件是制表符分隔的

  2. 你正在使用bash shell

  3. 数据文件中的id位于第一列

  4. 你的文件看起来像这样:

抬头

1   one
2   two
3   three
4   four
5   five

数据

1   col2    col3    col4    col5
2   col2    col3    col4    col5
3   col2    col3    col4    col5
4   col2    col3    col4    col5
5   col2    col3    col4    col5

我会使用awksed来完成这个任务,如下所示:

awk '{print "sed -i s/^"$1"/"$2"/ data"}' lookup | bash

这样做是通过每行查找并将以下内容写入stdout

sed -is/^1/one/ data

sed -is/^2/two/ data

等等。

它接下来将每一行传递给shell( | bash ),它将执行sed表达式。 -i for -i.bak ,您可能需要-i.bak来创建备份文件。 请注意,您可以将扩展名更改为您想要的任何内容。 sed正在查找行开头的id,如^ 您不希望替换可能不包含id的列中的“id”。

您的输出将如下所示:

one     col2    col3    col4    col5
two     col2    col3    col4    col5
three   col2    col3    col4    col5
four    col2    col3    col4    col5
five    col2    col3    col4    col5

当然,你的id可能不是简单的1比1,2比2等,但这可能会让你开始朝着正确的方向前进。 我非常宽松地使用右边的术语。

我这样做的方法是使用awk编写一个awk程序来处理更大的文件:

awk -f <(awk '
   BEGIN{print " BEGIN{"}
        {printf "      a[\"%s\"]=\"%s\";",$1,$2}
   END  {print "      }";
         print "      {$1=a[$1];print $0}"}
   ' lookup_file.txt
) data.txt

这假设id列是第1列; 如果没有,你需要改变$1 $1=a[$1]两个实例$1=a[$1]

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM