本文共 7002 字,大约阅读时间需要 23 分钟。
简介
awk是数据处理工具也是报告生成工具。相比于sed常常作用于一整行的处理,awk则比较倾向于将一行分为数个字段来处理。因此,awk相当适合处理小型的数据处理。默认情况下awk将下面的变量分配给在文本行中检测到的每个数据字段:$0:表示整行文本;$1:表示文本行中的第一个数据字段;$2:表示文本行中的第二个数据字段;$n:表示文本行中的第n个数据字段。
awk用法格式是:awk [options]‘模式类型1{动作1}’FILE1...
常用选项
选项 | 描述 |
-F FS | 指定描述一行中的数据字段的文件分隔符 |
-f awk_script | 指定读取程序的文件名,可指定载入脚本 |
-v VAR_VALUE | 定义awk程序中使用的变量和默认值 |
模式类型
空模式:没有指定任何模式,遍历文件中的每一行
1 2 3 4 5 6 | [root@zhao ~] # awk -F: '{print $1,$7}' /etc/passwd root /bin/bash bin /sbin/nologin daemon /sbin/nologin adm /sbin/nologin lp /sbin/nologin |
BEGIN模式:在执行所有awk脚本动作之前执行的预设类(准备)的工作
1 2 3 4 5 6 7 | [root@zhao ~] # awk -F: 'BEGIN {print "USERNAME SHELL"}{print $1,$7}' /etc/passwd USERNAME SHELL #使用BEGIN模式设定的预设字符 root /bin/bash bin /sbin/nologin daemon /sbin/nologin adm /sbin/nologin lp /sbin/nologin |
小拓展:分隔符包含字段分隔符(默认为空白符)和行分隔符(默认为换行符)其中使用FS:指定输入分隔符也是awk的内置变量;OFS指定输出分隔符;NF指定最后一个字段。
FS:指定输入分隔符
1 2 3 4 5 6 | [root@zhao ~] # awk 'BEGIN {FS=":"}{print $1,$7}' /etc/passwd root /bin/bash bin /sbin/nologin daemon /sbin/nologin adm /sbin/nologin lp /sbin/nologin |
OFS:指定输出分隔符
1 2 3 4 5 6 | [root@zhao ~] # awk 'BEGIN {FS=":";OFS="*********"}{print $1,$7}' /etc/passwd root********* /bin/bash bin********* /sbin/nologin daemon********* /sbin/nologin adm********* /sbin/nologin lp********* /sbin/nologin |
NF:指定最后一个字段
1 2 3 4 5 6 | [root@zhao ~] # df -lh | awk '!/^File/{printf"%-25s %s\n",$1,$NF}' /dev/mapper/vg0-root / tmpfs /dev/shm /dev/sda1 /boot /dev/mapper/vg0-usr /usr /dev/mapper/vg0-var /var |
END模式:在awk脚本动作执行完成之后做的简单的收尾操作,主要用于统计使用
1 2 3 4 5 6 7 8 | [root@zhao ~] # awk 'BEGIN {FS=":";OFS="***";print "USERNAME SHELL"}{print $1,$7}END {print "********END******"}' /etc/passwd USERNAME SHELL root*** /bin/bash bin*** /sbin/nologin daemon*** /sbin/nologin sshd*** /sbin/nologin tcpdump*** /sbin/nologin ********END****** |
正则表达式:(格式:/PATTERN/)表示对于被正则表达式匹配到的行进行操作,而并非所有行
1 2 3 4 5 6 7 | [root@zhao ~] # awk -F: '/in$/{print $1,$7}' /etc/passwd bin /sbin/nologin daemon /sbin/nologin adm /sbin/nologin lp /sbin/nologin mail /sbin/nologin uucp /sbin/nologin |
表达式:其值非0或为非空字符时满足条件,如:$1 ~ /foo/ 或 $1 == "magedu"
支持使用~(匹配)和!~(不匹配),>=,<=,>,< 等所有比较操作符
1 2 3 4 5 6 7 | [root@zhao ~] # awk -F: '$3>=50{print $1,$3}' /etc/passwd nobody 99 dbus 81 usbmuxd 113 vcsa 69 rtkit 499 avahi-autoipd 170 |
支持逻辑关系操作符
1 2 3 | [root@zhao ~] # awk -F: '$3>=500 && $7~/bash/{printf "%-15s %i %s\n",$1,$3,$7}' /etc/passwd user1 500 /bin/bash user2 501 /bin/bash |
指定匹配范围,格式为pat1,pat2
这个匹配模式类型很难理解,我们用一个例题来解析:
eg:匹配一个文件中以abc开头aaa结尾的字段
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | [root@zhao ~] # awk '/abc/,/aaa/{print $0}' awk.sh abc 3 #开始 cde 4 aaa 5 #结束 abc 6 #开始 aab 7 axd 8 hell0 9 aaa 10 #结束 abc how are you aaa #开始结束 abc 12 #开始 sss ddd sxd xvf #无结尾字段会直接遍历到文件尾部 |
输出动作介绍
1、print
print的使用格式:print item1, item2, ...
要点:
(1)、各项目之间使用逗号隔开,而输出时则以空白字符分隔;
(2)、输出的item可以为字符串或数值、当前记录的字段(如$1)、变量或awk的表达式;数值会先转换为字符串,而后再输出;
(3)、print命令后面的item可以省略,此时其功能相当于print $0, 因此,如果想输出空白行,则需要使用print"";
2、printf
printf命令的使用格式:printf format, item1, item2,...
要点:
(1)、其与print命令的最大不同是,printf需要指定format;
(2)、format用于指定后面的每个item的输出格式;
(3)、printf语句不会自动打印换行符;\n
其中format格式的指示符都以%开头,后跟一个字符;如下:
%c: 显示字符的ASCII码;
%d, %i:十进制整数;
%e, %E:科学计数法显示数值;
%f: 显示浮点数;
%g, %G: 以科学计数法的格式或浮点数的格式显示数值;
%s: 显示字符串;
%u: 无符号整数;
%%: 显示%自身;
在输出格式上常用修饰符:
N: 显示宽度;
-: 左对齐(默认为右对齐);
+:显示数值符号;
eg:
1 2 3 4 5 6 7 | [root@zhao ~] # awk -F: '{printf "%-15s %i\n",$1,$3}' /etc/passwd root 0 bin 1 daemon 2 adm 3 lp 4 sync 5 |
控制语句的使用
常见类型:if;while; for; case; do...while; break; continue; next
(1)、if-else
语法:if (condition){then-body} else {[else-body]}
解析:condition是判断条件通常为布尔表达式或逻辑表达式
1 2 3 4 5 6 7 8 | [root@zhao ~] # awk -F: '{if ($3==0) {print $1, "Adminitrator";} else { print $1,"Common User"}}' /etc/passwd root Adminitrator bin Common User daemon Common User adm Common User lp Common User sync Common User shutdown Common User |
1 2 | [root@zhao ~]# awk -F: -v sum= 0 '{if ($3>=500) sum++}END{print sum}' /etc/passwd 3 #所有UID大于 500 的用户个数 |
(2)、while
首先说明在awk中的循环不是循环每一行的而是循环切片之后的每一个字段的
语法: while(condition){statement1; statment2; ...}
1 2 3 4 5 6 7 | [root@zhao ~] # awk -F: '{i=1;while (i<=3) {print $i;i++}}' /etc/passwd root #i=1时输出第一个字段 x #i=2时输出第二个字段 0 #i=3时输出第三个字段 bin #第二行... x 1 |
1 2 3 4 5 6 | [root@zhao ~] # awk -F: '{i=1;while (i<=NF) { if (length($i)>=4) {printf "%s ", $i}; i++ ;};printf "\n"}' /etc/passwd root root /root /bin/bash /bin /sbin/nologin daemon daemon /sbin /sbin/nologin /var/adm /sbin/nologin /var/spool/lpd /sbin/nologin |
解析:length是awk的内置函数,获取字段的长度的;而这里length($i)指的是$i字段的长度。
(3)、do-while
和while循环的区别:while循环是当条件不满足时不会执行任何循环操作,而do-while是不论条件真假与否首先执行一次循环体,然后再去判断条件满足与否,满足继续执行不满足不再执行。也就是说不管条件满足与否,至少执行一次循环体。
语法: do{statement1, statement2, ...} while (condition)
1 2 3 4 5 6 | [root@zhao ~] # awk -F: '{i=4;do {print $i;i--}while(i>4)}' /etc/passwd 0 1 2 4 7 |
解析:此命令中的while循环并不成立但是还是执行了print$4这就是do-while的体系结构若还不太明白可对比使用:[root@zhao ~]# awk -F: '{i=4;while (i>4){print $i;i--}}'/etc/passwd此命令执行之后不会有任何执行结果。
(4)、for
语法: for ( 初始赋值; condition(变量条件);修正变量(初始值)) { statement1, statement2, ...}
1 2 3 4 5 6 7 8 | [root@zhao ~] # awk -F: '{for(i=1;i<=3;i++) print $i}' /etc/passwd root x 0 bin x 1 daemon |
(5)、case
语法:switch(expression) { case VALUE or /REGEXP/: statement1, statement2,... default:statement1, ...}
由于此语句不常使用所以不做深入研究,有意学习者请参考其他文章
(6)、break 和 continue
常用于循环或case语句中,具体使用方法和bash中基本类似,所以此处不做重点阐述
(7)、next
这个为awk的独有命令,表示提前结束对本行文本的处理,并接着处理下一行;
例如,显示其ID号为奇数的用户:
1 2 3 4 5 6 7 8 | [root@zhao ~] # awk -F: '{if($3%2==0) next;print $1,$3}' /etc/passwd bin 1 adm 3 sync 5 halt 7 operator 11 gopher 13 nobody 99 |
(8)、数组应用
数组:一组连续的可存储多个值内存空间,可使用数组索引(下标)来引用数组。
语法:array[index-expression]
index-expression可以使用任意字符串;需要注意的是,如果某数据组元素事先不存在,那么在引用其时,awk会自动创建此元素并初始化为空串;因此,要判断某数据组中是否存在某元素,需要使用index in array的方式。
若遍历数组中的每一个元素,需要使用如下的特殊结构:
语法:for (var in array) {statement1, ... }
其中,var用于引用数组下标,而不是元素值;
1 2 3 4 5 6 | [root@zhao ~] # awk -F: '$NF!~/^$/{BASH[$NF]++}END{for(A in BASH){printf "%15s:%i\n",A,BASH[A]}}' /etc/passwd /sbin/shutdown :1 /bin/bash :3 /sbin/nologin :31 /sbin/halt :1 /bin/sync :1 |
解析:$NF为最后一个字段,^$表示为空,BASH[$NF]表示下标为$NF数组,也就是说可能出现BASH[/bin/bash]等
awk的内置函数使用与介绍
split(string, array[, fieldsep [, seps ] ])
解析:将string表示的字符串以fieldsep为分隔符进行分隔,并将分隔后的结果保存至array为名的数组中;数组下标为从1开始的序列;
1 2 3 4 | [root@zhao ~] # netstat -tan | awk '/:80\>/{split($5,clients,":");ip[clients[4]]++}END{for(a in ip) print ip[a],a}' | sort -rn | head -50 100 172.16.18.11 1 * ##########此命令在不开启IPv6的centos6.4上执行的########### |
例题解析:split($5,clients,":")是使用冒号分割将第5段保存到clients数组中;IP[clients[1]]++}提取第一部分(IP地址)保存到IP这个变量中;{for(iin IP){print IP[i],i}}遍历IP地址并显示次数和IP地址;sort -rn 根据次数进行逆向排序,head -5O只取前50个。
例:取出当前使用比例已经大于20%的文件系统
1 2 | [root@zhao ~] # df -lh | awk '!/^File/{split($5,percent,"%");if(percent[1]>=20){print $1}}' /dev/mapper/vg0-usr |
length([string])
解析:返回string字符串中字符的个数;
substr(string, start[, length])
解析:取string字符串中的子串,从start开始,取length个;start从1开始计数;
system(command)
解析:执行系统command并将结果返回至awk命令
systime()
解析:取系统当前时间
tolower(s)
解析:将s中的所有字母转为小写
toupper(s)
解析:将s中的所有字母转为大写
至此awk的应用知识基本阐述完毕,如有错误或无阐述到位的问题请留言注明,大家的支持是我学习路上前进的动力!!
本文转自 z永 51CTO博客,原文链接:http://blog.51cto.com/pangge/1286728
转载地址:http://zqcrx.baihongyu.com/