awk实战2-将shell数组传递进awk的用法

1 本文适合读者

对awk数组用法比较熟悉的用户

2 问题描述

这是我们经常会处理的一种销售报表类型,某一行代表了某个商品在某个月的销量。

源文件 a.txt:

苹果    201801  300
苹果    201802  400
苹果    201804  500
苹果    201806  600
香蕉    201712  350
香蕉    201801  440
香蕉    201802  560
香蕉    201803  490
西瓜    201803  680
西瓜    201804  730
西瓜    201806  820

有时候,我们希望把每个月的销量放到一行上面,各个月份作为列字段。
如果只是要做单列数据到多列数据的转换,可直接利用上一篇文章
awk实战1-单列数据到多列数据的相互转换
介绍的方法,利用awk的二维数据即可。

目标文件 b.txt:

商品  201712  201801  201802  201803  201804  201805  201806
苹果            300    400              500            600
香蕉    350     440    560      490
西瓜                            680     730            820

但是,有时候我们希望输出的报表能加上字段头,而且字段头是按一定顺序排序的。
由于源文件的数据中是没有"201805"月份的数据的,所以仅使用上一篇文章的二维数组的用法,输出结果会缺失一部分想要的字段。

为了解决输出字段不全的问题,需要强制规定数组的下标内容,这时我们可以考虑通过shell把规定的数组内容传递进awk里面。

3 问题分析

在shell中,我们把字段头数组放在monthList变量中,如果仅仅是要把shell变量传递进awk,只需用-v var=${monthList}选项即可:

monthList="201711,201712,201801,201802,201803,201804,201805,201806"
# 变量传递的方法
awk -v arr=$monthList 'BEGIN{ print arr }'  a.txt

我们的目标是要把传递进去的数组变成下标,可以先用split()将字符串分割成数组,数组元素直接用来构造新的title数组的下标,这样awk里面就有了完整的下标。

awk -v arr=$monthList 'BEGIN{ split(arr,month,",");
  for (i in month) title[month[i]]=month[i]; 
  for (j in title) printf("\t%s",j); print("\n") }' a.txt
# 输出
  201711  201712  201801  201802  201803  201804  201805  201806

4 单列到多列转换,按指定的下标输出

针对源文件的完整的命令如下:

# 在shell中定义完整的字段头
monthList="201711,201712,201801,201802,201803,201804,201805,201806"

awk -F"\t" -v arr=$monthList              #传递变量
   'BEGIN{ split(arr,month,",");            #分割字符串
       for (i in month) title[month[i]]=month[i];       #构造下标
       printf("商品");  for (j in title) printf("\t%s",title[j]); print("\n") }   #打印字段头
   { type[$1]=$1; amount[$1,$2]=$3 }          #源文件的数据赋值给二维数组
   END { for (k in type) { 
       printf("%s",type[k]); for (l in title) {         #打印第一列
           if (amount[k,l] > 0) printf("\t%d",amount[k,l]);     #打印第2-第n列
           else printf("\t") };
       printf("\n") }}' a.txt

大功告成,你可以愉快的休息了。

5 说明

在awk中直接构造完整的数组下标也是可以的,但是awk脚本会显得臃肿,对于懒人就是要不断找到更省力的方法,在明确字段头范围的情况下,通过shell传递数组内容,不失为一种更简单的方法。特别是当脚本每次需要执行不同的字段头范围时,用shell来传递参数的优势会更明显。

awk实战系列
awk实战1-单列数据到多列数据的相互转换

awk实战3-将一个大文件按月拆成多个小文件
====本文为原创,转载请注明出处====

你可能感兴趣的:(awk实战2-将shell数组传递进awk的用法)