使用AWK进行文件内容join

使用AWK进行文件内容join

Yourtion 创作于:2020-07-26     全文约 1504 字, 预计阅读时间为 5 分钟

最近在做一个项目,需要在两个不同的数据源上导出两个 CSV 文件,同时对导出的文件进行类似于 SQL 的 join 操作,由于只是一个查询脚本,没办法修改程序或者数据库等功能,所以就想到将 csv 文件导出后,通过 Linux 自带的命令来完成内容的合并。

首选的工具自然是最强大的 AWK 了。

AWK是一种优良的文本处理工具,Linux及Unix环境中现有的功能最强大的数据处理引擎之一。 https://zh.wikipedia.org/zh-hans/AWK

需求

首先来看一导出的两个 csv 文件:

channel.csv 主要保存渠道 ID 与渠道名称的关系

id	Name
1	渠道1
2	渠道2
...

data.csv 记录每个渠道带来的 PV/UV 等信息

id	pv	uv	submit
2	4	3	2
12	1	1	0
3	1	1	0
...

需要的结果是将两个文档进行整合,输出一个完整的csv

channle	id	pv	uv	submit
渠道2	2	4	3	2
未知	12	1	1	0
渠道3	3	1	1	0

思路

其实解答的一个思路还是比较简单的,因为渠道 ID 本身不会重复,最简单的方法就是将其转换为一个字典,然后对于 data.csv 的内容根据 id 去字典中获取对应的渠道名称,最后组合到一起。

首先去网上找到了一个在 awk 内按行读取文件的方法,并根据需求将文件内容转换成一个数组(其实 awk 里面数组跟 map 是一样的)。最后再按行拼装数据即可。

需要处理一下渠道 ID 找不到对应的情况,很简单,同一个三元表达式即可 $1 in File ? File[$1] : "未知"

最终版本

首先是最核心的 join.awk ,实现了 awk 核心的逻辑:

function read_file_into_array(file, array, status, record) {
  while (1) {
    status = getline record < file
    if (status == -1) {
      print "Failed to read file " file;
      exit 1;
    }
    if (status == 0) break;
    split(record, a, "\t");
    array[a[1]] = a[2];
  }
  close(file);
}
BEGIN {
  read_file_into_array(CHANNEL, File);
} 
{ 
  if(NR == 1) {
    print "channel\tid\tpv\tuv\tsubmit"
    next
  }
  { printf("%s\t%s\t%s\t%s\t%s\t\n", ($1 in File ? File[$1] : "未知"),$1,$2,$3,$4) }
}

执行方法(通过 CHANNEL 参数传入变量):

$ awk -v CHANNEL=channel.csv -f join.awk  data.csv

运行结果:

代码详见:https://github.com/yourtion/BlogCodes/tree/master/awk_join

参考

  • https://www.unix.com/302417048-post3.html
  • https://www.unix.com/303007698-post1.html
  • https://blog.csdn.net/bitcarmanlee/article/details/51324585

原文链接:https://blog.yourtion.com/join-file-data-using-awk.html