awk是一种模式扫描和处理工具,相对于grep的查找,sed的编辑,它在对数据进行分析生成报表时显得尤为强大。awk通过逐行遍历一个或多个文件的方式,查找模式匹配到的行,而后以指定的分隔符(缺省为空格)进行切片,然后针对切片数据进行处理和分析。事实上,gawk有自己的语言,其本身就相当于一个解释器,允许用户创建简短的程序读取输入文件,对输入数据执行排序、计算以及生成报表操作,甚至可以类似bash shell实现诸如循环、数组、条件判断、函数、变量等功能,进而完成更为复杂的数据分析处理任务。
Gawk
gawk(GNU awk)是UNIX awk的GNU版,为方便linux用户使用,通常将/bin/awk以符号链接方式链接到/bin/gawk,以迎合用户的使用习惯。(下文有提到gawk的地方均以awk代替)
awk的使用方式
1、命令行方式
awk [-F field-separator] ‘COMMAND’inputfiles
//其中COMMAND是awk的执行命令,用来处理数据,[-F field-separator]是可选选项,inputfiles是待处理文件。
//awk使用中,需要处理的文件,逐行使用分隔符分割成若干个字段,称之为域,分隔符默认是空格,可使用-F选项来指定分隔符
2、shell脚本模式
将所需执行的awk命令插入awk脚本文件,然后在首行设置命令解释器为#!/bin/awk,通过键入脚本名的方式调用。
3、所有awk命令写入到一个单独的文件,当处理同一类文件需求时,使用awk -f awk-script inputfiles调用之,其中awk-script指awk脚本。
awk的基本语法
awk [OPTION] 'program' FILE1 FILE2…
program:PATTERN{ACTION STATEMENT} //program由语句组成,各语句之间使用;隔开,整个program要用单引号引起来
OPTION:选项
-F:指定分割符
例,指定分隔符为“:”,打印出系统上各用户名和morenshell
# awk -F: '{print $1,$7}' /etc/passwd
-v:指定变量
例,通过-v选项指定变量a=hello awk 然后将其打印出来
# awk -v a="hello awk" '{print a}'
另外,也可以通过特殊模式BEGIN(模式下述)来指定变量,如上例,也可以这样写
# awk 'BEGIN{a="hello awk"}{print a}'
-f:指定脚本文件
awk变量
awk的变量,可分类为内置变量和自定义变量
1、内置变量
2、自定义变量
自定义变量有两种方式(上文基本语法中已有示例,此处不再赘述),但是,在脚本中仍然可以声明变量。
(1)、awk -v VARIABLE_NAME VARIABLE_VALUE 'program' inputfiles
(2)、awk 'BEGIN{VARIABLE_NAME VARIABLE_VALUE}ACTION STATEMENT}' inputfiles
3、变量使用示例
(1)、FS输入分隔符,默认为空格
例如,默认分隔符使用awk提取/etc/inittab中的“#”,如下图可以看到,如果以空格分割,第一个域即为#(忽略最后一行)
# awk '{print $1}' /etc/inittab //效果如下(最后一行请忽略)
以“:”为分隔符,提取系统中用户名以及用户默认
# awk -v FS=":" '{print $1,$7}' /etc/passwd
(2)、输出分隔符,默认为空格(如上图上例显示结果),接上例,以:为输出分隔符显示输出结果
# awk -v FS=":" -v OFS=":" '{print $1,$7}' /etc/passwd
(3)、NR和FNR
显示/etc/{inittab,passwd}所有内容以及行数
# awk '{print NR,$0}' /etc/{inittab,passwd}//看下图,行数不分开计数
# awk '{print FNR,$0}' /etc/{inittab,passwd}//看下图,使用FNR单独计数行数
# awk 'BEGIN{print "filename","alone_lines","unit_lines"}{print FILENAME,NR,FNR}' /etc/{passwd,inittab,group}//还可以这样写来分别显示总行号和单独行号,此处不再贴图
(4)、ARGC显示参数个数
# awk -F: '{print $1}END{print ARGC}' /etc/passwd //如下图,显示参数为二(经验证,貌似program也被识别成为一个参数,再加上后面的文件故为2个参数?)
awk的模式
1、Regular Expression 正则表达式
如其名,使用正则表达式匹配模式,在需要注意的是,在awk中使用正则表达式,匹配字符串要使用双斜线括起来,而后匹配到的行将被切片并分析处理,反之将略过。
取出/etc/passwd中包含root的行并打印出用户名和默认shell
# awk -F: ‘/root/ {print $1,$7}' /etc/passwd
2、Expression 表达式,当表达式的值为真(非零或非空)的行被匹配,仅处理匹配到的行
# awk -F: '$3>=500{print $1,$2,$3}' /etc/passwd
在此列出awk的常用操作符
如果模式自身是=,要写为/=/
条件表达式:
selector?if-true-express:if-false-express 只能是表达式不能使语句
条件表达式中,“:”两侧仅允许使用表达式而不能使用语句
例
# awk -F: '$3>=500?utype="common user":utype="admin or system user"{print $1 "is" utype} /etc/passwd
3、range行范围,有两种方式来定义此范围
(1)、pattern1,pattern2
从匹配到pattern1的行开始到匹配到pattern2的行为知,此范围的行被awk action处理
# awk 'NR==1,NR==10{print $1,$3,$7} /etc/passwd
4、特殊模式BEGIN和END
(1)、BEGIN在读取任何输入之前执行一次语句
# awk 'BEGIN{FS=":";OFS=":"}/root/{print $1,$3,$7} /etc/passwd
(2)、END在读取所有输入之后执行一次语句
# awk 'BEGIN{FS=":";OFS=":"}/root/{print $1,$3,$7}END{print "The end!"}' /etc/passwd
5、空模式
如果不指定模式则匹配文件中的所有行
awk重定向
1、输出重定向
awk可以使用shell的重定向符重定向输出,同样>代表覆盖式输出,>>代表追加。
覆盖式重定向
追加重定向效果
2、输入重定向
输入重定向需用到getline函数。getline从标准输入、管道或者当前正在处理的文件之外的其他输入文件获得输入。它负责从输入获得下一行的内容,并给NF,NR和FNR等内建变量赋值。如果得到一条记录,getline函数返回1,如果到达文件的末尾就返回0,如果出现错误,例如打开文件失败,就返回-1,可以结合到while等流控制语句使用。
通过例子说明输入重定向用法
(1)、awk 'BEGIN{"date" | getline d; print d}'
getling函数读取date命令的输出结果并将其赋值给自定义变量d,然后打印变量d
(2)、awk 'BEGIN{"date" | getline d; split(d,mon); print mon[3]}'
getine函数读取date命令输出的结果并赋值给自定义变量d,split函数将变量d转化为数组mon,然后打印数组mon的第三个元素。
(3)、awk 'BEGIN{while("ls" | getline) print}'
getline函数读取ls命令的输出结果而后打印显示
awk之print和printf
1、print
用法:print item1,item2….
要点:
(1)、各item之间使用,号隔开,输出时默认以空格分隔
(2)、输出的item可以是字符串或数值、当前分隔出来的域(字段,如$1)、变量或awk的表达式,数值会隐式转换为字符串输出。
(3)、print后面的item项可以省略,此时相当于打印$0即整行内容;print ""表示打印空白行。
例:
# awk 'BEGIN{print "line1","line2","line3"}'
# awk -F: '{print $1,$3,$7}' /etc/passwd
2、printf
用来格式话打印输出内容
(1)、格式:
printf format,item1,ietm2,…
(2)、要点
printf需要指定format;
format用于指定后面每个item的格式;
printf不能自行换行,如需换行需给定\n;
使用修饰符可以使输出格式更加美观。
(3)、format的格式指示符,以%开始,后跟一个字符
%c:显示字符的ASCII吗
%d,%i:十进制整数
%e,%E:科学计数法显示数值
%f:显示浮点数本身
%g,%G:以科学计数法格式或浮点数显示数值
%s:显示字符串
%u:显示无符号整数
%%:显示%自身
修饰符
#:字段的显示宽度
.#:取值精度
-:左对齐
=+:显示数值的符号
(4)、例:
取出系统用户的用户名和默认shell,要求用户名左对齐,占用15个字符,字符串显示;要求默认shell左对齐,占用20字符,字符串显示
awk -F: ‘{printf "%-15s %-20s\n",$1,$7}' /etcpasswd
使用显示浮点数自身(%f)的方式显示,会自动补全精度,长于精度部分将会执行四舍五入
# awk 'BEGIN{printf "%f\n",3.15}'
当使用数字来定义字段占用字符长度时,要放在其它修饰符前面;小数点后面的数字代表精度
# awk 'BEGIN{printf "%-15.2\n",3.15}'
awk之action
1、常见action
(1)、表达式 Expression
(2)、控制语句 Control statements
(3)、组合语句 Commpound statments
(4)、输入语句 Input statments
(5)、输出语句 Output statements
2、awk常见控制语句以及使用示例
(1)、if-else语句 格式:if (condition) {then body} else {else body}
# awk -F: '{if($3>=500{print $1 "is a common user"} else {print $1 "is admin or systemuser"}' /etc/passwd
uid号大于等于500的显示为普通用户,小于500的显示为管理员或系统用户。
# awk -F: '{if(NF>=8){print}}' /etc/inittab
打印显示以冒号切割形成字段大于等于8的行
(2)、while语句 格式: 格式:while (condition) {while body}
awk '{i=1;while(i<=NF){printf "%s ",$i;i+=2}; print ""}' /etc/inittab
打印输出/etc/inittab中的奇数字段
打印出字符大于等于6的字段
# awk '{i=1;while(i<=NF{if(length($i<=6){print $i};i++}}' /etc/inittab
(3)、do-while循环 格式:格式:do {do-while body} while (condition)
# awk 'BEGIN{sum=0;i=0;do{sum+=i;i+=}while{i<=100};print sum;}'
求和1-100
(4)、for循环 格式:for (variable assignment; condition; iteration process) {for body}
# awk '{for(i=1,i<=NF,i+=2){printf "%s ",$1};print ""}' /etc/inittab
打印出/etc/inittab中的每行的奇数字段
for循环还可以用来遍历数组 格式:for (i in array) {for body}
# awk 'BEGIN{"date" | getline d; split(d,test);for (i in test) print test[i]}'
break 用于在满足条件的情况下跳出循环;continue用于在满足条件时忽略后面的语句,直接返回循环的顶端
(5)、next提前结束本行处理,进入下一行处理
取uid为奇数的用户和uid
# awk -F: '{if($3%2==0) next;print $1,$3}' /etc/passwd
(6)、数组
关联数组
array[index-expression]index-expression:可以使用任意字符串;如果某数组元素事先不存在,那么在引用时,awk会自动创建次元素并将其初始化为空串;因此,要判断某数组是否存在某元素,必须使用“index in array”这种格式A[first]="hello awk"print A[second]要遍历数组中的每一个元素,需要使用如下特殊结构:for (var in array) {for body}期中var会遍历array的索引,而非元素的值
(7)、awk的内置函数 split(string,array[,fieldsep[,seps]])能够将string标示的字符串以fieldsep为分隔符进行切片,并切片后的结果保存至array为名的数组中;数组下表从1开始
# awk 'BEGIN{split("root:x:0:0",user,":");for (i in user) print user[i]}'
由于本人水平有限,awk的使用先总结到这里吧,在以后的使用中再深入研究。
原创文章,作者:Silently,如若转载,请注明出处:http://www.178linux.com/6553