我有2个表格文件。 一个文件包含一个名为lookup_file.txt的50个键值的映射。 另一个文件具有30列和数百万行的实际表格数据。 data.txt我想用lookup_file.txt中的值replace第二个文件的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
现在,您需要先在用户标识列上对两个文件进行排序:
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,但是写一个包装这个脚本的脚本要比在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 -is/^"$1"/"$2"/ data"}' lookup | bash
这样做是通过每一行查询,并写下以下标准输出
sed -is/^1/one/ data
sed -is/^2/two/ data
等等。
它接下来将每行传递给shell( | bash
),它将执行sed
表达式。 -i对于-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=a[$1]
更改$1
两个实例