我有 2 个表格文件。一个文件包含 50 个键值的映射,仅称为lookup_file.txt。 另一个文件包含 30 列和数百万行的实际表格数据。data.txt 我想用lookup_file.txt 中的值替换第二个文件的id 列。.
我怎样才能做到这一点?我更喜欢在 bash 脚本中使用 awk。另外,我可以在 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 混合使用“排序”和“加入”,而不必在 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
这样做是通过每一行查找并将以下内容写入标准输出
sed -i s/^1/one/ data
sed -i s/^2/two/ data
等等。
接下来,它将每一行通过管道传送到 shell ( | bash
),shell ( ) 将执行sed
表达式。-i 对于就地,您可能需要-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
in 的两个实例$1=a[$1]