www.cnblogs.com/ruiyqinrui

开源、架构、Linux C/C++/python AI BI 运维开发自动化运维。 春风桃李花 秋雨梧桐叶。“力尽不知热 但惜夏日长”。夏不惜,秋不获。@ruiY--秦瑞

python爬虫,C编程,嵌入式开发.hadoop大数据,桉树,onenebula云计算架构.linux运维及驱动开发.

  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理
  1 AWK高级应用
  2 
  3  
  4 
  5 在进行数据割接时,需要对其导出脚本的日志文件进行统计分析以便核对是否有数据没有导出的情况!该日志文件的格式都是固定的,可以使用脚本来完成统计分析,而且脚本很灵活小巧。
  6 
  7  
  8 
  9          因为其复杂的语法和不明确的错误提示,造成awk的使用者进而远之,awk整体上比较难掌握。Awk是一种自解释的编程语言。而awk强大的文本处理功能正好能够胜任该工作。如果要格式化报文或从一个大的文本文件中抽取数据包,那么awk可以完成这些任务。它在文本浏览和数据的熟练使用上性能优异。
 10 
 11  
 12 
 13  
 14 
 15 Awk的特性网上有很多资料,大家可以参考一下。本次所运用的awk的特性有:
 16 
 17 Awk数组、printf修饰符、内置字符串函数、awk操作符、条件操作符。
 18 
 19  
 20 
 21          要想使用好awk,必须对awk的语法有一定的认识,否则你会被一大堆莫名其妙的错误所包围。
 22 
 23  
 24 
 25 Awk语句都是由模式和动作组成。模式的包括俩个关键字,BEGIN和END。BEGIN模式在awk遍历文本前调用,用来打印一些头信息或是声明一些全局变量。例如:
 26 
 27  
 28 
 29 Log.dat记录着日志信息,日志为日期-ip-手机号码。
 30 
 31 linux:/home/dss/dss/logs/msgs> cat log.dat
 32 
 33 20091111-172230-665-10.168.38.63-15035198115
 34 
 35 20091111-172230-738-10.168.38.65-13840784654
 36 
 37 20091111-172238-571-10.168.38.63-15929933330
 38 
 39 20091111-172238-668-10.168.38.63-13666463997
 40 
 41 20091111-172240-262-10.168.38.68-13591931301
 42 
 43 20091111-172242-24-10.168.38.63-15041615076
 44 
 45 20091111-172248-427-10.168.38.63-13409199466
 46 
 47  
 48 
 49  
 50 
 51 如果我想统计来自ip10.168.38.63的日志有几个,命令如下:
 52 
 53 linux:/home/dss/dss/logs/msgs> awk -F'-' 'BEGIN {printf "%-15s %s\n","IP","LOG"printf “===============================================”}{if($4~/10.168.38.63/)printf "%-15s %s\n", $4,$0}END{}' log.dat
 54 
 55 IP              LOG
 56 
 57 10.168.38.63    20091111-172230-665-10.168.38.63-15035198115
 58 
 59 10.168.38.63    20091111-172238-571-10.168.38.63-15929933330
 60 
 61 10.168.38.63    20091111-172238-668-10.168.38.63-13666463997
 62 
 63 10.168.38.63    20091111-172242-24-10.168.38.63-15041615076
 64 
 65 10.168.38.63    20091111-172248-427-10.168.38.63-13409199466
 66 
 67  
 68 
 69 其中头信息IP和LOG在遍历log.dat前打印!
 70 
 71 而END模式在遍历完文件最后执行,可以用于信息汇总,或打印结束日志。
 72 
 73  
 74 
 75 实际动作需要包含在{}之间,如果不指明,默认动作是打印所有行。
 76 
 77  
 78 
 79 Awk的域和记录,awk执行时,其浏览域标记为$1,$2… $n。这种方法称为域标识。使用这些域标识将更容易对域进行进一步处理。$0为匹配整行,看个例子:
 80 
 81  
 82 
 83 linux:/home/dss/dss/logs/msgs> awk -F'-' '{print $4, $5}' log.dat
 84 
 85 10.168.38.63 15035198115
 86 
 87 10.168.38.65 13840784654
 88 
 89 10.168.38.63 15929933330
 90 
 91 10.168.38.63 13666463997
 92 
 93 10.168.38.68 13591931301
 94 
 95 10.168.38.63 15041615076
 96 
 97 10.168.38.63 13409199466
 98 
 99  
100 
101 以上命令只打印第4列和第5列。并且域分隔符为-,默认的域分隔符为空格,使用-F参数指定域分隔符。
102 
103 awk有许多内置变量用来设置环境信息。这些变量可以被改变。下面列出一些最常使用的一些变量,并给出其基本含义。
104 
105 ARGC 命令行参数个数
106 
107 ARGV 命令行参数排列
108 
109 ENVIRON 支持队列中系统环境变量的使用
110 
111 FILENAME awk浏览的文件名
112 
113 FNR 浏览文件的记录数
114 
115 FS 设置输入域分隔符,等价于命令行- F选项
116 
117 NF 浏览记录的域个数
118 
119 NR 已读的记录数
120 
121 OFS 输出域分隔符
122 
123 ORS 输出记录分隔符
124 
125 RS 控制记录分隔符
126 
127  
128 
129 awk有许多强大的字符串函数,这些字符串函数在处理文本方面起着很重要的作用。通过这些内置字符串处理函数可以很随意的定义一些自己想要的函数。下面为awk中内置字符串处理函数。
130 
131 gsub (r, s) 在整个$0中用s替代r
132 
133 gsub (r, s, t) 在整个t中用s替代r
134 
135 index (s , t) 返回s中字符串t的第一位置
136 
137 length ( s ) 返回s长度
138 
139 match (s , r) 测试s是否包含匹配r的字符串
140 
141 split (s , a , fs) 在f s上将s分成序列a
142 
143 sprint (fmt , exp) 返回经f m t格式化后的e x p
144 
145 sub (r, s) 用$ 0中最左边最长的子串代替s
146 
147 substr (s , p) 返回字符串s中从p开始的后缀部分
148 
149 substr (s , p , n) 返回字符串s中从p开始长度为n的后缀部分
150 
151  
152 
153 如下我只要使用index和substr函数就可以组合出很强大的自定义函数:
154 
155 function substrmid(src, begin, end) {
156 
157         startindex=index(src,begin) + length(begin)
158 
159         temp=substr(src,startindex)
160 
161         endindex=index(temp,end) - length(end)
162 
163         return substr(src,startindex,endindex)
164 
165     }
166 
167    
168 
169     function substrbefore(src, end) {
170 
171         endindex=index(src,end)-length(end)
172 
173         return substr(src,0,endindex)
174 
175     }
176 
177    
178 
179     function substrafter(src, begin) {
180 
181         startindex=index(src,begin) + length(begin)
182 
183         return substr(src,startindex)
184 
185 }
186 
187  
188 
189 自定义函数substrbefore(src, end)是截取src中end之前的字符串,substrmid(src, begin, end)是截取src中介于begin和end之间的字符串(不包含begin和end),substrend(src, end)是截取src中end之后的字符换,例如:
190 
191 Substrmid(“2009-11-01”, “-”,”-”)返回字符串11,substrbefore(“2009-11-01”, “-”)返回2009,substrafter(“11-01”, “-”)返回01,可以根据自己的需要构造一些自定义函数。
192 
193  
194 
195 最后简单介绍一下awk中的数组应用。Awk是一种类似自解释语言,其中的数据应用可以很好的完成数据统计工作。Awk中数组使用无需提前声明。数组使用前,不必定义,也不必指定数组元素个数。经常使用循环来访问数组。下面是一种循环类型的基本结构
196 
197 For (element in array ) print array[element]
198 
199 Awk的特性介绍完了,现在开始实战了!
200 
201  
202 
203 这个小工具的要求是这样的,在做数据割接时,将数据库的数据按照路由规格利用数据库提供的批量导出工具把数据导出成dat文件,需要对数据库的日志进行统计分析,看看每个分库每个分表导出多少条记录!
204 
205  
206 
207 SQL3104N  The Export utility is beginning to export data to file
208 
209 "./PISADB10/CONTACTINFO977_1_3717.dat".
210 
211 中间有若干行无关紧要的内容
212 
213 Number of rows exported: 24040
214 
215 其中的./PISADB10/CONTACTINFO977_1_3717.dat和Number of rows exported: 24040为关键信息。
216 
217 PISADB10表示分库10,CONTACTINFO977_1_3717.dat表示分表1。而Number of rows exported: 24040为导出多少行。而日志文件里有上万行这样的日志,而且大概有100多个日志,要求这个小功能能够做到批量统计。
218 
219  
220 
221 首先使用grep命令将相关重要信息提取出来,以免其他信息造成干扰。使用命令
222 
223 Grep –E ‘^Number of rows exported|^".*(CONTACTINFO|DS_CLIENT_MAPPING|GROUPCONTACTMAP)\w*.dat’ db2export_1.sh.log
224 
225 命令输出格式为:
226 
227 。。。
228 
229 "./PISADB5/CONTACTINFO472_1_12012.dat".
230 
231 Number of rows exported: 40
232 
233 "./PISADB5/CONTACTINFO473_1_12033.dat".
234 
235 Number of rows exported: 24040
236 
237 "./PISADB5/CONTACTINFO474_1_12054.dat".
238 
239 Number of rows exported: 40
240 
241 "./PISADB5/CONTACTINFO475_1_12075.dat".
242 
243 Number of rows exported: 40
244 
245 "./PISADB5/CONTACTINFO476_1_12096.dat".
246 
247 Number of rows exported: 40
248 
249  
250 
251 以上信息才是我想要的。将结果交给awk来处理完成,由于awk本身的机制,awk只能按行来处理文件,一次只能处理一行,所有以上信息处理还需要一些特殊的适配。Awk一次只读一样,如果该行不包含Number说明该行为分库和分表信息行,将其暂存起来,等到下一行Number行时,再对其进行处理。这里可以使用awk中的条件操作符if语句来完成,{if($0!~/Number/) tmp=$0} {if($0~/Number/)print “This is a number line and it’s owner is ”tmp},其中if的条件判断无需用()引起来,但是未避免语句错误最好将所有的条件判断都用()扩起来。!~为不匹配~为匹配,//之间可以输入正则表达式。
252 
253  
254 
255 当行为number行时,需要将其中的关键数字截取出来做汇总。
256 
257 if($0!~/Number/){
258 
259     num=substrafter($0,” exported: ”)
260 
261 }
262 
263 这样就将num截取出来了,剩下的就是做汇总信息了!完整的脚本如下:
264 
265  
266 
267  grep -E '^Number of rows exported|^".*(CONTACTINFO|DS_CLIENT_MAPPING|GROUPCONTACTMAP)\w*.dat' db2export_1.sh.log | awk '
268 
269  
270 
271     function substrmid(src, begin, end) {
272 
273         startindex=index(src,begin) + length(begin)
274 
275         temp=substr(src,startindex)
276 
277         endindex=index(temp,end) - length(end)
278 
279         return substr(src,startindex,endindex)
280 
281     }
282 
283    
284 
285     function substrbefore(src, end) {
286 
287         endindex=index(src,end)-length(end)
288 
289         return substr(src,0,endindex)
290 
291     }
292 
293    
294 
295     function substrafter(src, begin) {
296 
297         startindex=index(src,begin) + length(begin)
298 
299         return substr(src,startindex)
300 
301  
302 
303 BEGIN {
304 
305     flag=""
306 
307     total=0
308 
309     table=""
310 
311 }
312 
313  
314 
315 {
316 
317     if($0!~/Number/) {
318 
319         flag=$0
320 
321     }
322 
323 }
324 
325  
326 
327 {
328 
329     if($0~/Number/) {
330 
331     print $0
332 
333     num=substrafter($0,"exported: ")
334 
335     partdb=substrmid(flag, "/", "/")
336 
337     fromtable=substrmid(flag, "_", "_")
338 
339     P[partdb]=P[partdb]+num
340 
341     S[fromtable]=S[fromtable]+num
342 
343     total=total+num
344 
345     }
346 
347 }
348 
349  
350 
351 END {
352 
353     print "Total number of export: "total
354 
355     for(p in P){
356 
357         print p" number of export: "P[p]
358 
359     }
360 
361     for(s in S){
362 
363         print "parttable "s"  number of export:  "S[s]
364 
365     }
366 
367 } 

 

posted on 2013-08-10 23:41  秦瑞It行程实录  阅读(385)  评论(0编辑  收藏  举报
www.cnblogs.com/ruiyqinrui