免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 3775 | 回复: 3
打印 上一主题 下一主题

转一篇《AWK 关联数组的一个应用》看不大懂的说 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2009-05-09 04:48 |只看该作者 |倒序浏览
在 awk 中数组叫做关联数组(associative arrays),因为下标记可以是数也可以是串。awk 中的数组不必提前声明,也不必声明大小。数组元素用 0 或空串来初始化,这根据上下文而定。例如:
  1:可以用数值作数组索引(下标)
Myarray[1]=”xu sihua”
Myarray[2]=”780927”
  2:可以用字符串作数组索引(下标)
Myarray[“first”]=”xu”
Myarray[“last”]=”si hua”
Myarray[“birth”]=”780927”
  使用中 print myarray[1] 将得到”xu sihua” 而 print myarray[2] 和 print[“birth”] 都将得到 ”780927” 。
  问题的提出
  在我们的生产系统中有一个应用每天都有大量的数据库插入操作,这些操作被记录在了日志文件中,而我们的目的就是从这些日志文件中提取所需要的数据。日志文件的数据格式如下:
--sert into table_a ( field1,field2,field3 ...) values ( 3,1,'xx',...) ;
--sert into table_a ( field4,field1,field2 ...) valuse ( 'yyy',2,675 ,...);
--sert into table_a ( field1,field8,fieldN ...) valuse ( 'zzz','ccc','eee' ,...);


其中 field1、field2、fieldN 等是数据库表 table_a 中的字段,每条语句中的字段数不定,顺序也不定,但是所有的字段都是表 table_a 内的字段,values 中的值有字符串也有整数。我想通过上面的文件产生下面格式的数据:
field1_value|field2_value|field3_value|.....|fieldN_value|
field1_value|field2_value|field3_value|.....|fieldN_value|
field1_value|field2_value|field3_value|.....|fieldN_value|
  具体实现
  实现思想很简单,我创建一个数组(AWK 中的关联数组),用字段名作为数组的下标(键),用每条记录 Values 中的值来填充这个数组,最后按照自己所需要的格式输出,下面的代码我省略了一些不必要的部分,仅仅是为了把问题讲清楚:
BEGIN {
print "n Extract some data from CDR Data Package. ","n",
"Processing begins at:",strftime("%Y%m%d%H%M%S", systime())
#为了记录程序的运行时间我在程序开始时输出当前的系统时间,用到了 AWK 的内置函数 strftime.
}
{ #下面创建了数组 ta_record,数组的下标就是记录中的字段名
ta_record["field1"]=""
ta_record["field2"]=""
ta_record["field3"]=""
ta_record["field4"]=""
…………
ta_record["fieldn"]=""
#下面把每条记录中的字段与对应的值存入关联数组中
for (i=5; i<=(NF-1)/2;i++)==============为什么是从5开始,到字段数目的一半截止?
{
   if(i%2 > 0)
   {
    value=tolower($(i+(NF-3)/2 ))
    if( match(value,/^'/) ) #有些字段的值是用单引号引起来的这个需
#要去掉。
     {
     #这里用了 AWK 的 tolower 和 substr 函数
 ta_record[tolower($i)]=substr(value,2,length(value)-2)
     }
    else #字段的值如果不带单引号直接赋值即可。
    ta_record[tolower($i)]=value
   }
}
#根据自己的需要输出数据,可以加多个过滤条件,例如:
#只输出字段 fieldx 的值为 3 和字段 fieldy 的值为 12 的记录
if( (NR+1)%10000 == 0) {printf("%s",". ")}
if(ta_record["fieldx"] == 3 || ta_record["fieldy"] == 12 )
{
printf("%s%s%s%s%s%s%s%s%s%s%sn",
ta_record["field1"],"|",
ta_record["field2"],"|",
ta_record["field3"],"|",
ta_record["field4"],"|"
,ta_record["field5"],"|",
ta_record["fieldN"],"|")
>> ta_record["fieldz"]
#这里用ta_record["fieldz"]作为输出文件是有好处
#的,如果fieldz有多个可能的值,例如1,3,5
#那么输出的结果就会生成文件名是1,3,5的三
#个文件,分别记录了fieldz的值为1,3,5的结果,文
#件名是动态产生的,当然您也可以写一个固定的
#文件名把所有结果输出到#一个结果文件中。
}
}
#最后,在程序运行完成时输出当前的系统时间,这样就可以大概算出这个
#程序的总运行时间了。
END { print "n","Processing ends at: ",strftime("%Y%m%d%H%M%S", systime()) }
  为什么使用 AWK 来解决这个问题呢?
  为什么使用AWK处理这些数据呢,首先因为 AWK 是高效的文本处理工具,而且在几乎所有的 Unix/Linux 中都存在, 另外 AWK 十分高效,对文本数据的处理极具针对性先对于其它语言有很多方便的特性。
  程序运行后得到了下面这样的结果:
11|991|1540|13579210134|00992927770589|00992927770589|
33|996|77|13565078660|95533|099195533|
3|991|30|9918814897|200|09063353941|
  现在你需要的数据提取出来了,数据怎么使用取决于你的需要,我用 Oracle 数据库的 SQL Loader 工具把这些数据导入到一个临时表中,然后通过 SQL 操作处理剩下的工作。附件中有真实的数据和和完整的代码清单。
  运行环境
  Red Hat Enterprise Linux AS release 3 (Taroon) (Kernel 2.4.21-4.ELsmp)
  GNU Awk 3.1.1

论坛徽章:
0
2 [报告]
发表于 2009-05-09 08:39 |只看该作者
说几点自己对awk数组的基础认识
1、数组定义:a[1]="ab";a[12]=24;a["xyz"]=15;a["mn1"]="ab"
     a是数组名,1、12、xyz、mn1是数组下标,awk对下标是以字符串形式来处理的,即使a[12],也是把12当字符串
2、打印指定数组元素,接上例: print a[1];print a["xyz"]
3、打印所有数组元素。 for (j in a) print a[j]
     打印顺序是随机的

进阶点的:
1、数组定义时,下标中可以有变量、函数,比如a[substr($0,1,2)"xyz"]=1
     a[var"xyz"]=1    #var是awk里的变量
   a[$1"#"$2]=1
2、数组嵌套定义:  a[1]="bb";b[a[1]]=1  后面的数组b定义相当于b["bb"]=1

暂时想到这么多,学awk数组掌握这些基础知识后多看几个版里数据处理的实例,就会学习到应用数组的技巧。

论坛徽章:
9
2015亚冠之阿尔纳斯尔
日期:2015-09-10 16:21:162015亚冠之塔什干火车头
日期:2015-07-01 16:23:022015年亚洲杯之巴勒斯坦
日期:2015-04-20 17:19:46子鼠
日期:2014-11-13 09:51:26未羊
日期:2014-08-28 18:13:36技术图书徽章
日期:2014-02-21 09:30:15酉鸡
日期:2014-01-14 11:12:49天蝎座
日期:2013-12-09 17:56:53平安夜徽章
日期:2015-12-26 00:06:30
3 [报告]
发表于 2009-05-09 08:42 |只看该作者
原帖由 laohuanggua 于 2009-5-9 04:48 发表
在 awk 中数组叫做关联数组(associative arrays),因为下标记可以是数也可以是串。awk 中的数组不必提前声明,也不必声明大小。数组元素用 0 或空串来初始化,这根据上下文而定。例如:
  1:可以用数值作数 ...


红色的,因为数据如下
--sert into table_a ( field1,field2,field3 ...) values ( 3,1,'xx',...) ;
--sert into table_a ( field4,field1,field2 ...) valuse ( 'yyy',2,675 ,...);
--sert into table_a ( field1,field8,fieldN ...) valuse ( 'zzz','ccc','eee' ,...);

field1等字段是从$5位开始的,到$NF一半就没了

论坛徽章:
0
4 [报告]
发表于 2009-05-10 23:13 |只看该作者
原帖由 HH106 于 2009-5-9 08:42 发表


红色的,因为数据如下
--sert into table_a ( field1,field2,field3 ...) values ( 3,1,'xx',...) ;
--sert into table_a ( field4,field1,field2 ...) valuse ( 'yyy',2,675 ,...);
--sert into table ...



大赞!您这一下就点到正题


明天再看一下这个例子。也谢谢ywlscpl 兄。您是awk高手。
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP