之前我介绍过sed,cut,tr,grep等等的命令来对文本进行处理,但是有时候发现这些命令并不能完全的满足我们的需求,直到我学习了awk,感觉以前有些比较繁琐的命令可以根据awk轻易解决,这些命令的结合会给我们处理文本带来巨大的便利。


一、awk简介

    awk其名称得自于它的创始人 Alfred Aho 、Peter Weinberger 和 Brian Kernighan 姓氏的首个字母。实际上 AWK 的确拥有自己的语言: AWK 程序设计语言 , 三位创建者已将它正式定义为“样式扫描和处理语言”。它允许您创建简短的程序,这些程序读取输入文件、为数据排序、处理数据、对输入执行计算以及生成报表,还有无数其他的功能。

    awk是一个强大的文本分析工具,相对于grep的查找,sed的编辑,awk在其对数据分析并生成报告时,显得尤为强大。简单来说awk就是把文件逐行的读入,以分隔符将每行切片,切开的部分再进行各种分析处理。

    awk有3个不同版本: awk、nawk和gawk,未作特别说明,一般指gawk,gawk 是 AWK 的 GNU 版本。

    awk程序的报告生成能力通经常使用来从大文本文件里提取数据元素并将它们格式化成可读的报告。最完美的样例是格式化日志文件  


 二、awk用法

    awk 'BEGIN{ commands } pattern{ commands } END{ commands }'

    这条指令和以前的命令有些不同,他的命令有执行顺序:

        第一步:运行BEGIN{ commands }语句块中的语句。

        第二步:从文件或标准输入(stdin)读取一行。然后运行pattern{ commands }语句块,它逐行扫描文件,从第一行到最后一行反复这个过程。直到文件所有被读取完成。

        第三步:当读至输入流末尾时。运行END{ commands }语句块。

        BEGIN语句块在awk開始从输入流中读取行之前被运行,这是一个可选的语句块,比方变量初始化、打印输出表格的表头等语句通常能够写在BEGIN语句块中。

        END语句块在awk从输入流中读取全然部的行之后即被运行。比方打印全部行的分析结果这类信息汇总都是在END语句块中完毕,它也是一个可选语句块。

        pattern语句块中的通用命令是最重要的部分,它也是可选的。假设没有提供pattern语句块,则默认运行{ print },即打印每个读取到的行。awk读取的每一行都会运行该语句块。

    这三个部分缺少任何一部分都可以。

    选项:

        -F 指明输入时用到的字段分隔符 

        -v var=value: 自定义变量

        -f scripfile 从脚本文件中读取awk命令


 三、awk的变量

    变量分为内置和自定义变量 

    内置变量:

     FS:输入字段分隔符,默认为空白字符 

[root@localhost(cyn) ~]$ awk -v FS=':' '{print $1,FS,$3}' /etc/passwd    #设置默认字符为:
root : 0
bin : 1

    OFS:输出字段分隔符,默认为空白字符 

[root@localhost(cyn) ~]$ awk -v FS=':' -v OFS='!' '{print $1,$3}' /etc/passwd     #设置输出为!
root!0
bin!1

    RS:输入记录分隔符,指定输入时的换行符,原换行符仍有效   

[root@localhost(cyn) ~]$ awk -v RS=' ' '{print }' /etc/passwd   #以前是按行进行操作,现在是按照RS定义的来,换行符依然是换行符
ftp:x:14:50:FTP
User:/var/ftp:/sbin/nologin
nobody:x:99:99:Nobody:/:/sbin/nologin
systemd-network:x:192:192:systemd
Network
Management:/:/sbin/nologin

    ORS:输出记录分隔符,输出时用指定符号代替换行符     #制定输出时的换行符

[root@localhost(cyn) ~]$ awk -v RS=' ' -v ORS='###' '{print }' /etc/passwd
ftp:x:14:50:FTP###User:/var/ftp:/sbin/nologin
nobody:x:99:99:Nobody:/:/sbin/nologin
systemd-network:x:192:192:systemd###Network###Management:/:/sbin/nologin
dbus:x:81:81:System###message###bus:/:/sbin/nologin
polkitd:x:999:998:User###for###polkitd:/:/sbin/nologin

    NF:字段数量 

###[root@localhost(cyn) ~]$ awk -F: '{print NF}' /etc/passwd       
7
7
7
7

    NR:行号 

[root@localhost(cyn) ~]$ awk '{print NR}' /etc/passwd
1
2
3
4
5
6

 FNR:各文件分别计数,行号 

[root@localhost(cyn) ~]$ awk '{print FNR}' /etc/fstab /etc/passwd   #统计两个文件的行号
1
2
。。。
11
12
1
2

ARGC:命令行参数的个数 

[root@localhost(cyn) ~]$ awk '{print ARGC}' /etc/fstab /etc/passwd    #最前面的awk也算一个参数为$0
3
3
3
3

ARGV:数组,保存的是命令行所给定的各参数 

[root@localhost(cyn) ~]$ awk '{print ARGV[1]}' /etc/fstab /etc/passwd 
/etc/fstab
/etc/fstab
[root@localhost(cyn) ~]$ awk '{print ARGV[0]}' /etc/fstab /etc/passwd 
awk
awk
[root@localhost(cyn) ~]$ awk '{print ARGV[2]}' /etc/fstab /etc/passwd 
/etc/passwd
/etc/passwd

    自定义变量

[root@localhost(cyn) ~]$ awk -v test='hello' '{print test}' /etc/passwd
hello 
hello


 四、格式化输出

     格式化输出:printf “FORMAT”, item1, item2, ... 

    (1) 必须指定FORMAT 

    (2) 不会自动换行,需要显式给出换行控制符,\n 

    (3) FORMAT中需要分别为后面每个item指定格式符 

    格式符:与item一一对应 

        %c: 显示字符的ASCII码 

        %d, %i: 显示十进制整数 

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

        %f:显示为浮点数 

        %g, %G:以科学计数法或浮点形式显示数值 

        %s:显示字符串

        %u:无符号整数 

        %%: 显示

        %自身 

    修饰符:

         #[.#]:第一个数字控制显示的宽度;第二个#表示小数点后精度,%3.1f 

        -: 左对齐(默认右对齐) 

        %-15s +:显示数值的正负符号 %+d

[root@localhost(cyn) ~]$ awk -F: '{printf "%-15s%-5s\n",$1,$6}' /etc/passwd 
root           /root
bin            /bin 
daemon         /sbin


 五、awk操作符

    算术操作符: 

        x+y, x-y, x*y, x/y, x^y, x%y 

        -x: 转换为负数 

        +x: 转换为数值 

    字符串操作符:没有符号的操作符,字符串连接

    赋值操作符: 

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

        ++, -

    比较操作符: ==, !=, >, >=, <, <= 

    模式匹配符:

        ~:左边是否和右边匹配包含

        !~:是否不匹配  

[root@localhost(cyn) ~]$ awk -F: '($0 ~ /root/ ){print $1}' /etc/passwd    #支持正则
root
operator


 六、awk控制语句

    awk支持while,if  else,for循环,这部分

利用while计算100之内的和
[root@localhost(cyn) ~]$ awk BEGIN'{i=1;while(i<=100){sum+=i;i++};print sum}'
利用forjisuan 100之内的和
[root@localhost(cyn) ~]$ awk BEGIN'{for(i=1;i<=100;i++){sum+=i};print sum}'
利用for和if else计算奇数和
[root@localhost(cyn) ~]$ awk 'BEGIN{sum=0;for(i=1;i<=100;i++){if(i%2==0)continue;sum+=i};print sum}'


 七、awk数组

    关联数组:array[index-expression] • index-expression: 

        (1) 可使用任意字符串;字符串要使用双引号括起来 

        (2) 如果某数组元素事先不存在,在引用时,awk会自动创建此元素,并将其值初始化为“空串” 

    若要判断数组中是否存在某元素,要使用“index in array”格式进行遍历

    若要遍历数组中的每个元素,要使用for循环 

    for(var in array) {

        for-body

    } 

    注意:var会遍历array的每个索引 

[root@centos6(cyn) ~]$ awk -F: '{line[$7]++}END{for(i in line){print i,line[i]}}' /etc/passwd   #统计文件中某个单词出现的次数
/sbin/shutdown 1
/bin/bash 1
/sbin/nologin 27
/sbin/halt 1
/bin/sync 1

[root@centos6(cyn) ~]$ netstat -tan|awk '/^tcp/{state[$NF]++}END{for(i in state){print i,state[i]}}' #统计监听出现的次数
ESTABLISHED 1
LISTEN 10

 

 八、awk函数

    1.数值处理: 

        rand():返回0和1之间一个随机数 

[root@centos6(cyn) ~]$ awk 'BEGIN{srand(); for (i=1;i<=10;i++)print int(rand()*100) }' 
17
4
57
54
43
32
87
90

    2.字符串处理:

    length([s]):返回指定字符串的长度 

    sub(r,s,[t]):对t字符串进行搜索r表示的模式匹配的内容,并将第一个匹配的内容替换为s 

[root@centos6(cyn) ~]$ echo "2018:08:29 10:08:30" |awk 'sub(/:/,"-",$1)'
2018-08:29 10:08:30

    gsub(r,s,[t]):对t字符串进行搜索r表示的模式匹配的内容,并全部替换为s所表示的内容 

[root@centos6(cyn) ~]$ echo "2018:08:29 10:08:30" |awk 'gsub(/:/,"-",$1)'
2018-08-29 10:08:30
[root@centos6(cyn) ~]$ echo "2018:08:29 10:08:30" |awk 'gsub(/:/,"-",$0)'
2018-08-29 10-08-30

    split(s,array,[r]):以r为分隔符,切割字符串s,并将切割后的结果保存至array所表示的数组 中,第一个索引值为1,第二个索引值为2,…

[root@centos6(cyn) ~]$ netstat -tan |awk '/^tcp\>/&& !($5 ~ "*") {split($5,ip,":");count[ip[1]]++}END{for(i in count){print i,count[i]}}'
172.18.253.52 1
172.18.253.114 1
172.18.251.79 1
172.18.250.40 1
172.18.254.218 1
172.18.254.139 2

    3.自定义函数,awk的函数不需要加权限,直接运行

[root@centos6(cyn) ~]$ vim fun.awk
[root@centos6(cyn) ~]$ cat fun.awk 
function max(a,b){
	a>b?var=a:var=b
	return var
}
BEGIN{m=3;n=2;print max(m,n)}
[root@centos6(cyn) ~]$ awk -f fun.awk 
3


 九、awk中调用shell命令

    system命令 

    空格是awk中的字符串连接符,如果system中需要使用awk中的变量可以使用空格分隔,或者说除了 awk的变量外其他一律用""引用起来。 

[root@centos6(cyn) ~]$ awk 'BEGIN{score=100;system("name=zhangsan;echo $name score is "score )}'
zhangsan score is 100
[root@centos6(cyn) ~]$ awk BEGIN'{system("hostname")}'
centos6