grep,sed和awk称作文本处理三剑客,下面介绍一下awk的基本用法

awk:man手册上的意思为:pattern scanning and processing language;

     意为样式扫描和处理语言 

awk是一个数据处理工具,常用于一整行的处理,将读入的行进行分段,

   每一行的每个字段有变量名称的,$1,$2..$NF.

awk的强大之处还在于它是一个格式化的报告生成工具;支持文本处理过滤,脚本编程,

在一个语句内部还可实现循环。

一:语法格式:

awk [option] 'script' file1,file2,...

awk [option] 'PATTERN {action}'

awk ‘条件类型1{动作1}条件类型2{动作2}...’ filename

awk 'BEGIN{print "start"}PATTERN{ commands }END{print "end"}' filename

     BEGIN语句块 +  能够使用模式匹配的通用语句块 + END语句块 

常用的表示:

默认分隔符是空格

-F:指定字段分隔符

$0表示引用整行

$1表示第一行

$2表示第二行

NF:每一行拥有的字段总数

NR:目前awk所处理的是第几行数据

FS:目前的分隔符,默认是空格

$NF:每一行的最后一个字段

-v OFS= 表示输出的段分隔符是什么

 

二:printf:格式化的显示命令

printf format,itam1,itam2,...

要点:

1、与print命令的最大不同是,printf需要指定格式

2、format用于指定后面的每个item的输出格式

3、printf不会自动打印换行符 

format格式的指示符都以%开头,后跟一个字符,如:

%c:显示字符的ASCII码

%d,%i:十进制

%e:%E:科学计算法显示数值

%f:显示浮点数

%s:显示字符串

%u:无符号整数

%%:显示%自身

 

修饰符:

N:显示宽度

-:左对齐

+:显示数值符号

 

默认是右对齐的

例1:

[root@localhost ~]# awk '{printf "%10s,%s\n", $1,$2}' a.txt

   welcome,to

       how,to

[root@localhost ~]# awk '{printf "%-10s%s\n", $1,$2}' a.txt

welcome   to

how       to

 

三:awk的操作符

1、算术操作符

-x:负值

+x:转换为数值

x^y,x**y:次方

x*y:乘法

x/y

x+y

x-y

x%y

2:赋值操作符

= += -= /= %= ^= **= ++ --

3:比较操作符

x < y

X <= y

X > Y

x >= y

x == Y

x != y

x ~ y  取模能够被匹配;y是模式

x !~ y  取模不能够被匹配

例2:awk -F: '$1 ~ /^root/ {print $3,$4,$NF}' /etc/passwd

 $1 ~ /^root/  用来做模式匹配的,如果能够匹配第一字段开头是root的,

 则显示它的$3,$4,$NF

 

四:作匹配的情况:

1、正则表达式:格式为/regular expression/

[root@localhost ~]# awk -F : '/bash/{print $1,$NF}' /etc/passwd

root /bin/bash

student /bin/bash

visitor /bin/bash

2、表达式:其值为非0或为非空时满足条件;如 %1 ~ /foo 

或$1 == "hadoop" 使用运算符~(匹配)和!~(不匹配)

[root@localhost ~]# awk -F: '$3>=500{print $3,$NF}' /etc/passwd

65534 /sbin/nologin

500 /bin/bash

501 /bin/bash

3、指定的匹配范围的

格式:pat1,pat2   

/bash/,/awk/  第一次被/bash/匹配的开始,到第一次被/awk匹配的结束

4、BEGIN/END 特殊模式,仅在awk命令执行前运行一次或结束前运行一次

# awk -F: 'BEGIN{print "USER       UID"}{printf "%-12s%s\n",$1,$3}END{print "Over"}' /etc/passwd

USER       UID   ##加上用户和UID号

root        0

bin         1

daemon      2

adm         3

...

Over      ##提醒结束的信息

//使用BEGIN和ENG分别在输出的内容的开头和结尾加上我们希望的信息;

 

五:在awk中可以使用各种控制语句:

1、if-else
语法: if (condition) {then-body} {[ else-body ]}
 
  1. eg: 
  2. # awk -F: '{if ($1==“root”) print $1,"Admin"; else print $1,"common  
  3. User"}' /etc/passwd 
  4. root admin 
  5. bin common user 
  6. daemon common user 
  7. ... 
  8.  
  9. //如果第一个字段是“root”的话就显示它是Admin,否则显示时"common  
  10. User";这样用一条命令就实现了对用户的用户的分类 
  11.  
  12. 同样,/etc/passwd中第三个字段是用户的ID号,我们知道只有root的ID号为零 
  13. ,那么以此也可用来区分root和普通用户: 
  14. # awk -F: '{if ($3==0) print $1,"Admin";else print $1, "common  
  15. user"}' /etc/passwd 
  16.  
  17. 也可将结果以左对齐较整齐的输出: 
  18. # awk -F: '{if ($3==0) printf "%-15s: %s\n",$1,"Admin";else printf  
  19. "%-15s: %s\n", $1, "common user"}' /etc/passwd 
  20.  
  21. 用if-else求和: 
  22. # awk -F: -v sum=0 '{if ($3<=500) sum++}END{print sum}' /etc/passwd 

2、while语句

语法:while (condition)(statement1;statement2;...)

  1. # awk -F: '{i=1;while (i<=3) {print $i;i++}}' /etc/passwd 
  2. # awk -F: '$1~/root/{i=1;while (i<=NF) {print $i ;i+=2}}' /etc/passwd 
  3. root 
  4. root 
  5. /bin/bash 
  6. //先选取匹配root的行,然后显示奇数片段的结果 
  7.  
  8. 所以在awk中,可以实现将(如/etc/passwd中的)每一行切片处理(以:为分隔符),然后对每一片段的结果做处理 

3、do-while

语法:do (statement1; statement2;...) while (contion)

先执行一次循环再做判断,这和while语句不同

满足条件就执行循环,不满足就退出

# awk -F: '{i=1;do {print $i;i++} while(i<=3)}' /etc/passwd

4、for语句

用于循环次数已知的循序;

语法:for (初始值;判断条件;变量条件) {stattement1;statement2,...}

  1. # awk -F: '{for(i=1;i<=3;i++){print $i}}' /etc/passwd 
  2.  
  3. //while,do-while和for循序有时能都可用于循环,类似于C语言风格;其中fo 
  4. r最常用 
  5.  
  6. for循环还可以用来遍历属组元素: 
  7. 语法:for (i in array) {statement1;statement2;...} 
  8. # awk -F: '$NF!~/^$/{BASH[$NF]++}END{for(A in BASH){printf  
  9. "%15s:%i\n",A,BASH[A]}}' /etc/passwd 
  10.       /bin/sync:1 
  11.       /bin/bash:3 
  12.   /sbin/nologin:28 
  13.      /sbin/halt:1 
  14.  /sbin/shutdown:1 
  15.  
  16. 求1-100之和: 
  17. # seq 1 100 | awk '{a+=$1}END{print a}' 
  18. 5050 

5、case

语法:switch (expression) {case VALUE or /REDEXP/: statement1;statement2;...}

6、break,continue

常用于循环和case语句中

7、next.

提前结束对文本的处理,并接着处理下一行

 

六、awk中数组的使用:

array[index-expression]

index-expression可以使用任意字符串,但如果某数组元素事先不存在,那么在引用时,awk会自动创建次元素并初始化为空串;

因此,要判断某数组中是否存在某元素,需要使用Index in array的方式

要遍历属组中的每一个元素,使用如下方式:

语法:for (var in array) {statement1;statement2;...}

//var用于引用数组下标

例3:用awk显示netstat中每一种状态的和:

  1. 例:用awk显示netstat中每一种状态的和: 
  2.  
  3. [root@localhost ~]# netstat -ant 
  4. Active Internet connections (servers and established) 
  5. Proto Recv-Q Send-Q Local Address               Foreign Address             State       
  6. tcp        0      0 127.0.0.1:2208              0.0.0.0:*                   LISTEN       
  7. tcp        0      0 0.0.0.0:111                 0.0.0.0:*                   LISTEN       
  8. tcp        0      0 0.0.0.0:80                  0.0.0.0:*                   LISTEN       
  9. tcp        0      0 0.0.0.0:946                 0.0.0.0:*                   LISTEN       
  10. tcp        0      0 0.0.0.0:22                  0.0.0.0:*                   LISTEN       
  11. tcp        0      0 127.0.0.1:631               0.0.0.0:*                   LISTEN       
  12. tcp        0      0 127.0.0.1:25                0.0.0.0:*                   LISTEN       
  13. tcp        0      0 127.0.0.1:6011              0.0.0.0:*                   LISTEN       
  14. tcp        0      0 127.0.0.1:2207              0.0.0.0:*                   LISTEN       
  15. tcp        0    132 172.16.14.14:22             172.16.0.1:49750            ESTABLISHED  
  16.  
  17. # netstat -ant|awk '$1~/tcp/{S[$NF]++}END{for(i in S) print i,S[i]}' 
  18. LISTEN 9 
  19. ESTABLISHED 1 
  20.  
  21. ##$NF是最后一段的值;即LISTEN或ESTABLISHED 
  22. ##把最后一个片段当做数组的下标 
  23. ##任何一个变量没声明之前它的初始值为零,$[$NF]开始时为0, 
  24. ## S[$NF]++变量整个循环后,所有LISTEN的个数保存在S[LISTEN]中, 
  25. ## 所有ESTABLISHED的个数保存在S[ESTABLISHED]中; 
  26. ##i是数组的下标;代表的值有ESTABLISHED和LISTEN 
  27. ##上面命令中的S[i],当i为LISTEN时,表示S[LISTEN]的个数 
  28. ##当i为ESTABLISHED;表示S[ESTABLISHED]的个数 
  29.  
  30. 对输出结果规范化: 
  31. # netstat -ant|awk '$1~/tcp/{S[$NF]++}END{for(i in S) printf "%12s:%s\n", i,S[i]}' 
  32.       LISTEN:9 
  33.  ESTABLISHED:1 
  1. 例4:统计/etc/passwd最后一个非空片段的个数 
  2. # awk -F: '$NF!~/^$/{S[$NF]++}END{for(i in S)printf "%-15s: %s\n", i,S[i]}' /etc/passwd 
  3. /bin/sync      : 1 
  4. /bin/bash      : 3 
  5. /sbin/nologin  : 28 
  6. /sbin/halt     : 1 
  7. /sbin/shutdown : 1 
  8.  
  9. 例5:统计访问日志中访问本服务器的ip次数: 
  10. # cd /usr/local/apache/logs 
  11. # awk '{IP[$1]++}END{for(i in IP) print i,IP[i]}' access_log  
  12. 192.168.0.243 137 
  13. ##由此可见,awk是个报告生成工具 

七、awk的内置函数

split(string,array [,fieldsep [seps] ])

功能:将string表示的字符串以fieldsep为分隔符进行分割,

并将分割后的结果保存至array为名字的数组中

  1. 如: 
  2. netstat -ant|awk  
  3. '/:80/{split($5,clients,":");IP[clients[1]]++}END{for(i in  
  4. IP){print i,IP[i]}}' |sort -rn | head -50 
  5.  
  6. ##过滤“:80”的行,对第五个字段以":"进行切割,将结果保存至clients中, 
  7. ##IP[clients[1]]是一个数组,数组的下标是切割后的客户端IP, 
  8. 最后显示每一个IP的访问次数 
  9. ##将一个数组的内容当做另一个数组的下标 
  10. ##当一个IP的访问次数过多时,有故意攻击之嫌,这时可采取措施应对