CWYAlpha

Just another WordPress.com site

Thought this was cool: awk快速教程

leave a comment »


http://www.hcs.harvard.edu/~dholland/computers/awk.html

http://www.vectorsite.net/tsawk_1.html

http://stud.wsi.edu.pl/~robert/awk/

http://gregable.com/2010/09/why-you-should-know-just-little-awk.html

1、打印列

假设数据如下:

07.46.199.184 [28/Sep/2010:04:08:20] "GET /robots.txt HTTP/1.1" 200 0 "msnbot"
123.125.71.19 [28/Sep/2010:04:20:11] "GET / HTTP/1.1" 304 -  "Baiduspider"

打印整行,$0是整行:

$ cat ./test.txt | awk '{print $0}'
07.46.199.184 [28/Sep/2010:04:08:20] "GET /robots.txt HTTP/1.1" 200 0 "msnbot"
123.125.71.19 [28/Sep/2010:04:20:11] "GET / HTTP/1.1" 304 -  "Baiduspider"

其中{和}之间的是命令,一般来说,对输入的每一行执行一遍。

对于$x,默认用任何空白符号做分割。

$x表示第x列,例如:

$ echo 'this is a test' | awk '{print $3}'
a
$ cat ./test.txt | awk '{print $1}'
07.46.199.184
123.125.71.19

2、列数变量NF

有的时候,你并不知道数据会有多少列,可以用NF打印列数量:

$ echo 'this is a test' | awk '{print NF}'
4

照葫芦画瓢,可以使用$NF表示最后一列:

$ echo 'this is a test' | awk '{print $NF}'
test

甚至可以使用组合的NF:$(NF-1),表示倒数第2列:

$ echo 'this is a test' | awk '{print $1, $(NF-1)}'
this a

3、行数变量NR

与NF对应,NR表示行数,例如,可以给前面的log文件的前面,加上行号:

$ cat ./test.txt | awk '{print "<"NR"> "$0}'
<1> 07.46.199.184 [28/Sep/2010:04:08:20] "GET /robots.txt HTTP/1.1" 200 0 "msnbot"
<2> 123.125.71.19 [28/Sep/2010:04:20:11] "GET / HTTP/1.1" 304 -  "Baiduspider"

如上:注意在print之内的其他变量要用引号””。

4、指定其他(非空白)分隔符

还是对于如下数据,我们想提取出日期,例如“28/Sep/2010”:

07.46.199.184 [28/Sep/2010:04:08:20] "GET /robots.txt HTTP/1.1" 200 0 "msnbot"
123.125.71.19 [28/Sep/2010:04:20:11] "GET / HTTP/1.1" 304 -  "Baiduspider"

我们来做个拆解动作,首先提取“[28/Sep/2010:04:08:20]”,然后再提取“[28/Sep/2010”:

其中-F为指定分隔符

$ cat ./test.txt | awk '{print $2}' | awk -F : '{print $1}'
[28/Sep/2010
[28/Sep/2010

我们也可以把分隔符写在awk命令内。

$ cat ./test.txt | awk '{print $2}' | awk 'BEGIN{FS=":"}{print $1}'
[28/Sep/2010
[28/Sep/2010

到了这一步,我们发现还剩下最前面一个[没有被去掉,可以sed搞定。

$ cat ./test.txt | awk '{print $2}' | awk 'BEGIN{FS=":"}{print $1}' | sed 's/^\[//'
28/Sep/2010
28/Sep/2010

5、数值计算

加法:

$ echo 5 4 | awk '{print $1 + $2}'
9

除法:

$ echo 5 4 | awk '{print $1 / $2}'
1.25

最诡异的,默认乘法:

$ echo 5 4 | awk '{print $1 $2}'
54

6、多行语句

在一个语句块{}中,awk也能写多语句、循环,语句之间用分号;分开。变量直接指定。

对每一行处理:求该行所有列的均值:

$ cat ./num.txt 
1 2
3 4
5 6
liheyuan@coder4-pc:~$ cat ./num.txt | awk '{sum=0;for(i=1;i<NF;i++) sum+=$i;print sum/NF}'
0.5
1.5
2.5

7、多个块

上面的例子很傻,一般来说,我们是要求所有数值的均值

我们可以使用END,END之后的语句块{}表示当所有Input执行完毕后,再执行它。

例如,求所有输入数值的均值:

$ cat ./num.txt 
1
3
5
liheyuan@coder4-pc:~$ cat ./num.txt | awk '{sum+=$1} END {print sum/NR}'
3

Block可以有条件的执行,当$1==0时,执行:

awk ' $1==0 { print $2 }'

8、加入If逻辑

还是上述日志分析,如果我们只想打印HTTP Response状态为200的,怎么办呢?

$ cat ./test.txt | awk '{ if ( $(NF-2) == 200 ) {print $0} }'
07.46.199.184 [28/Sep/2010:04:08:20] "GET /robots.txt HTTP/1.1" 200 0 "msnbot"

9、循环逻辑

假设如下的文件:

$ cat ./num.txt 
1
2
3
4
5

累加,并逐行输出:

$ cat ./num.txt | awk '{a+=$1 ; print a}'
1
3
6
10
15

累加,最后只输出一行:

$ cat ./num.txt | awk '{a+=$1}END{print a}'
15

10、printf

awk支持类似C语言的printf格式。

跳过第1列,打印剩余的列,同时打印行号,列号:

$ cat ./num.txt | awk '{for(i=1;i<=NF;i++) printf "<%d,%d> %s \n", NR, i, $i ;}'
<1,1> 1 
<2,1> 3 
<3,1> 5

 

 

 
from 四号程序员: http://www.coder4.com/archives/3764

Written by cwyalpha

四月 11, 2013 在 3:23 上午

发表在 Uncategorized

发表评论

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / 更改 )

Twitter picture

You are commenting using your Twitter account. Log Out / 更改 )

Facebook photo

You are commenting using your Facebook account. Log Out / 更改 )

Google+ photo

You are commenting using your Google+ account. Log Out / 更改 )

Connecting to %s

%d 博主赞过: