[英]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解决方案。
假设如下:
文件是制表符分隔的
你正在使用bash shell
数据文件中的id位于第一列
你的文件看起来像这样:
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
我会使用awk
和sed
来完成这个任务,如下所示:
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.