awk指令,给我的感觉是可以在任何一截的管道设卡,通过正则,排序,取值,等等的操作取出所需要的值。
昨天处理了一个需求,如果取出排名前100 request最慢的请求,log是这样的
2012-08-31 00:00:39,571 slow /area.htm id:531 TIME:117
2012-08-31 00:00:42,262 slow req com.taobao.pegasus.travel.biz.bo.impl.MywayManagerImpl.getBeenToPageWithComment TIME:76
2012-08-31 00:00:42,297 slow /area.htm id:356 TIME:176
2012-08-31 00:00:46,082 slow req com.taobao.pegasus.travel.biz.bo.impl.MywayManagerImpl.getBeenToPageWithComment TIME:55
2012-08-31 00:00:51,257 slow /note_view.htm id:8415 TIME:131
2012-08-31 00:00:54,128 slow req com.taobao.pegasus.travel.biz.bo.impl.MywayManagerImpl.getBeenToPageWithComment TIME:64
2012-08-31 00:00:54,134 slow /area.htm id:8038 TIME:126
2012-08-31 00:00:58,103 slow req com.taobao.pegasus.travel.biz.bo.impl.MywayManagerImpl.getBeenToPageWithComment TIME:59
2012-08-31 00:00:58,108 slow /area.htm id:3887 TIME:101
2012-08-31 00:00:59,425 slow /note_view.htm id:9584 TIME:111
2012-08-31 00:01:00,060 slow /note_view.htm id:11035 TIME:134
2012-08-31 00:01:01,781 slow req com.taobao.pegasus.travel.biz.bo.impl.WeatherManagerImpl.getWeather TIME:98
2012-08-31 00:01:01,782 slow /weather.htm TIME:101
2012-08-31 00:01:06,073 slow /note_view.htm id:10941 TIME:102
时间在最后面,
于是写了这样的一个awk
cat travel_time.log | grep -v "slow req" | sed 's/TIME://g' | awk '($4~/\.htm/){print $NF " " $4}'|sort -nr|head -100
慢慢来整理吧。
awk 基本的结构是 pattern {action} 用一个大括号把要执行的东西包起来,它以line为导向,就是上一个的结果会成为下一个的流输入,比如下面的
echo 'aaaa bbbb' | awk '{print $1} , 它会把echo的字符串作为输入, 然后以空格为split,打印出第一个数据。
$的意思是The dollar sign means that we are refering to a field or column in the current line
通过命令行的形式,awk可以轻松的处理文本,比如有这样的一个文本
gold 1 1986 USA American Eagle gold 1 1908 Austria-Hungary Franz Josef 100 Korona silver 10 1981 USA ingot gold 1 1984 Switzerland ingot gold 1 1979 RSA Krugerrand gold 0.5 1981 RSA Krugerrand gold 0.1 1986 PRC Panda silver 1 1986 USA Liberty dollar gold 0.25 1986 USA Liberty 5-dollar piece silver 0.5 1986 USA Liberty 50-cent piece silver 1 1987 USA Constitution dollar gold 0.25 1987 USA Constitution 5-dollar piece gold 1 1988 Canada Maple Leaf
名字为coins.txt, 指令:
awk '/gold/' coins.txt
可以遍历上面的coins.txt文件,取出里面没一行中包含gold的行,然后输出,如果我们把这个指令和之前的{}组合起来,可以创造一个更强大的功能
awk '/gold/ {print $5,$6,$7,$8}' coins.txt
将以gold开头的,coins的名字打印出来
这是一个最简单的awk指令的模式
awk <search pattern> {<program actions>}
首先awk会遍历输入文件的每一行,从中找出满足search pattern的行,然后通过actions输出需要展现的内容,print的作用就很明显了,用来打印,后面跟的$4,$5被称为field variable。记录了每一行变量的顺序,其中变量$0代表了正行的信息,这里便有了等价三兄弟:
awk '/gold/' conis
awk '/gold/ {print}' conisawk '/gold/ {print $0}' conis
awk指令还能添加if的判断,如果我们想看看coins中哪些coins是在1980年之前铸造的
awk '{if ($3 < 1980) print $3, " ",$5,$6,$7,$8}' coins.txt
这个例子有一些新的概念:
1 没有search pattern 如果木有,则awk会匹配所有的行
2 在print里面添加自己的元素
3 如果if语句匹配成功,就执行后面的print
awk还能有wc的作用,看这个例子
awk 'END {print NR,"coins"}' coins.txt
为了解释这个例子,需要引入一个awk的语法:
awk 'BEGIN {<initializations>} <search pattern 1> {<program actions>} <search pattern 2> {<program actions>} ... END {<final actions>}'
begin意指在awk开始文件流扫描之前的一些初始化的操作。之后的是一系列最简单的awk格式,awk 扫描每一行,然后和每一个search pattern比较,然后输出。在扫描完之后,END用来执行在结束之前的最后的输出。
所以,
awk 'END {print NR,"coins"}' coins.txt
的意思是在最后的时候打印出NR+coions,其中NR是一个变量,表示记录的数量。(这个是awk自己定义的变量,还有一些其他的,比如NF)
NR - Number of Record - 当前处理的行是第几行(因为awk是流处理工具,一行一行处理的,所以NR在不停的自增1)
FNR - File Number of Record - 当前处理的行是当前处理文件的第几行
NF - Number of Fileds - 当前行有多少列数据(这个在每行都会根据设定的分割符重新计算,默认分割符是任务长个空白符)其中 $NF 指最后一列
现在给出一个更复杂的,比如现在的金币价值425美元,我们想知道总共的价格,
awk '/gold/ {ounces += $2} END {print "value = $" 425*ounces}' coins.txt
这里的ounces就是我们自己定义的变量,不断的把第二列的重量加起来,最后在结束之前调用END的print打印出价值