全称:Aho,Weiberger,Kernighan,是三个作者的名字,所以简称为awk
awk:报告生成器,主要用来格式化文本输出的,它能够实现在处理文本文件时对文档中的字段有条件的显示,而且将显示的结果用非常美观的文本形式给予输出。我们所用的awk其实就是gawk,他是一个符号链接指向gawk的。
gawk pattern scanning and processing language:模式扫描及处理语言awk其实就是一个解释器,是一个编程语言的解释器,从本质上来讲他也是一个编程语言,支持条件判断、数组、循环等各种各样一个编程语言当中几乎所有的功能。因此我们又可以把gawk称为一个脚本语言解释器,他所支持的是一个单独的脚本编程语言的功能。和bash编程语言一样,也是过程式编程语言。另外gawk也有自己内置的变量,允许用户自定义变量。
awk的基本用法: awk [options] 'program' FILE ...paogram的组成:PATTERN{ACTION STAEMRNTS(动作语句)}:可以有多个语句,语句之间用分号分割。
选项:
-F:指明输入时用到的字段分隔符:从文件中读取数据时以什么当作分割符
-v var=varlaue:用于实现自定义变量: awk常用的输出命令: 1、print print item1,item2,...
要点:
(1)逗号分隔符:
(2)输出的各item可以是字符串,也可以是数值,也可以是当前记录的字段,变量或awk的表达式
(3)如省略item,相当于print $0(打印整行) 2、变量 内建变量
FS:input field seperator:输入字段分隔符,默认为空白字符
OFS:output field seperator:输出字段分隔符,默认为空白字符
RS:input record seperator:输入时的换行符
ORS:output record seperator:输出时的换行符
NF:number of field:每一行的字段数量
{print NF},{print $NF}
NR:num of record:行数
FNR:各文件分别计数:行数
FILENAME:当前文件名
ARGC:命令行参数的个数
ARGV:是一个数组,保存的是命令行所给定的各参数
自定义变量
(1)-v var=value
变量名区分字符大小写:
(2)在program中直接定义 3、printf 格式化输出:printf FORMAT,item1,item2,...
(1)FORMAT必须给出
(2)不会自动换行,需要显示给出换行控制符,\n
(3)FORMAT中需要分别为后面的每个intem指定一个格式化符号
格式符:
%c:显示字符的ASCII码
%d,%i:显示十进制整数
%e,$E:科学计数法数值显示
%f:显示为浮点数
%g,%G:以科学计数法或浮点形式显示数值
%s:显示字符串
%u:无符号整数
%%:显示%号自身
修饰符:
#[.#]:第一个数字控制显示的宽度:第二个#显示小数点后的精度:
-:左对齐
+:显示数值的符号 4、操作符 算术操作符:
x+y,x-y,x*y,x/y,x^y,x%y
-x
+x:转换为数值:
字符串操作符:没有符号的操作符,字符串连接的意思
赋值操作符:
=,+=,-=,*=,/=,%=,^=
++,--
比较操作符:
>,>=,<,<=,!=,==
模式匹配符:
~:是否匹配
!~:是否不匹配
逻辑操作符:
&&,||,!
函数调用:
function_name(argu1,argu2,...)
条件表达式:
selector?if-true-expression:if-fales-expressiion
示例:格式化显示/etc/passwd文件中用户名是普通用户还是系统用户还是管理员
awk -F: '{$3>=500?usertype="Common User":usertype="Sysadmin or Sysuser";printf "%15s:%-s\n",$1,usertype}' /etc/passwd 5、pattern (1)empty:空模式,匹配每一行
(2)/regular expression/:仅处理能够被此处模式匹配到的行
(3)relational expression:关系表达式:结果有“真”有“假”,结果为“真”才会被处理;
真:结果为非0值为真,非空字符串也为真
(4)line ranges:行范围,指明起始行,指明结束行
startline,endline:/pat1/,/pat2/
注意:不支持直接给出数字的格式,须使用如下格式
示例:显示/etc/passwd中第2行到第10行的用户名
~]# awk -F: '(NR>=2&&NR<=10){print $1}' /etc/passwd
(5)BENGIN/END模式
BENGIN{}:仅在开始处理文件中的文本之前执行一次:
END{}:仅在文本处理完成之后执行一次 6、常用的action (1)Expressions:表达式
(2)Control statements:控制语句,if,while,for等
(3)Compound statemens:组合语句
(4)input statemens:输入语句
(5)output statemens:输出语句 7、控制语句 if(condition) {statmens}
if(condition) {statmens} else {statemens}
while(condition) {statmens}
do {statmens} while(condition)
for(expr1;expr2;expr3) {statemens}
break
continue
delete arrar[index]
delete array
exit
{ statements}
控制语句说明
(1)if-else
语法:if(condition) statement [else statement]
~]# awk -F: '{if($3>=500) {printf "Common user: %s\n",$1} else {printf "root or Sysuser: %s\n",$1}}' /etc/passwd
~]# awk -F: '{if($NF=="/bin/bash") print $1}' /etc/passwd
示例:显示/etc/fstab文件中字段数大于5的行
~]# awk '{if(NF>5) print $0}' /etc/fstab
示例:显示当前使用空间大于20的设备名称
~]# df -h | awk -F[%] '/^\/dev/{print $1}' |awk '{if($NF>=20) print $1}'
使用场景:对awk取得的整行或某个字段做条件判断
(2)while循环
语法:while(condition) statemnt
条件为真进入循环:条件为假退出循环
使用场景:对一行内的多个字段逐一类似处理时使用:对数组中的各元素逐一处理时使用:
~]# awk '/^[[:space:]]*linux16/{i=1;while(i<=NF) {print $i,length($i); i++}}' /etc/grub2.cfg
~]# awk '/^[[:space:]]*linux16/{i=1;while(i<=NF) {if(length($i)>=7) {print $i,length($i); i++}}' /etc/grub2.cfg
(3)do-while循环
语法:do statement while(condition)
意义:至少执行一次循环体
(4)for循环
语法:for(expr1;expr2;expr3) statement
for(variable assignment;conditiion;iteration process) {for-body}
~]# awk '/^[[:space:]]*llinux16/{for(i=1;i<=NF;i++) {print $i,length($i)}}' /etc/grub2.cfg
特殊用法:
能够遍历数组中的元素:
语法:for(var in array) {for-body}
(5)switch语句
语法:switch(expression) {case VALUE1 or /REGEXP/: statement;case VALUE2 or /REGEXP2/: statement;...;default: statement}
(6)break和continue
break [n]
continue
(7)next
提前结束对本行的处理而直接进入下一行
示例:显示ID号为偶数的用户
~]# awk -F: '{if($3%2!=0) next; print $1,$3}' /etc/passwd 8、array 关联数组:array[index-expression]
index-expreesion
(1)可使用任意字符串;字符串要使用双引号
(2)如果某数组元素事先不存在,在引用时,awk会自动创建此元素,并将其值初始化为“空串”
如要判断数组中是否存在某元素,要使用“index in array”格式进行
weekdays["mon"]="Monday"
如要遍历数组中的每个元素,要使用for循环
for(var in array) {for-boby}
~]# awk 'BEGIN{weekdays["mon"]="Monday";weekdays["tue"]="tuesday";for(i in weekdays) {print weekdays[i]}}'
注意:var会遍历array的每个索引
示例:显示各端口的状态次数
~]# netstat -tan | awk '/^tcp\>/{state[$NF]++}END{for(i in state) { print i,state[i]}}'
示例:显示每个ip地址访问httpd服务的次数
~]# awk '{ip[$1]++}END{for(i in ip) {print i,ip[i]}}' /var/log/httpd/access_log
练习1:统计/etc/fstab文件中每个文件系统类型出现的次数
~]# awk '/^UUID/{fs[$3]++}END{for(i in fs) {print i,fs[i]}}' /etc/fstab
练习2:统计指定文件中每个单词出现的次数;
~]# awk '{for(i=1;i<=NF;i++){count[$i]++}}END{for(i in count) {print i,count[i]}}' /etc/fstab 9、函数 (1)内置函数
数值处理
rand():返回0和1之间一个随机数
字符串处理
length([s]):返回指定字符串的长度
sub(r,s,[t]):以r表示的模式来查找t所表示的字符串中的匹配的内容,并将其第一次出现替换为s所表示的内容
gsub(r,s,[t]):以r表示的模式来查找t所表示的字符串中的匹配的内容,并将其所有出现均替换为s所表示的内容
split(s,a,[r]):以r为分割符切割字符s,并将切割后的结果保存至a所表示的数组中
~]# netstat -tan | awk '/^tcp\>/{split($5,ip,":");count[ip[1]]++}END{for (i in count) {print i,count[i]}}'
(2)自定义函数 练习:
显示/etc/fstab文件后五行的第2和第4个字段
]# tail -5 /etc/fstab |awk '{print $2,$4}'显示/etc/fstab文件后五行的第2和第4个字段,并且在输出的行首显示“ali”字符,在行尾显示数字“1”。
]# tail -5 /etc/fstab |awk '{print "ali",$2,$4,1}'显示/etc/passwd文件中的第1个字段,要求awk内建变量输入分割符为冒号
]# awk -v FS=':' '{print $1}' /etc/passwd使用冒号为分割符显示/etc/passwd文件中的用户名
]# awk -F: '{print $1}' /etc/passwd使用输入分隔符为冒号和输出分隔符为冒号显示/etc/passwd文件的第1,3,7字段(以冒号为分割符显示/etc/passwd中用户名,UID,shell类型)
]# awk -F':' -v OFS=':' '{print $1,$3,$7}' /etc/passwd以空格为属入换行符显示/etc/passwd文件
]# awk -v RS=' ' '{print }' /etc/passwd显示/etc/fstab文件中每行的字段数
]# awk '{print NF}' /etc/fstab显示/etc/passwd文件中每行的最后一个字段
]# cat /etc/passwd |awk -F':' '{print $NF}'分别显示/etc/fstab和/etc/issue文件的行数
]# awk '{print FNR}' /etc/fstab /etc/issue格式化显示/etc/passwd文件中每行的用户名,UID,shell类型,要求对应显示username,uid,shelltype
]# awk -F: '{printf "username: %s, uid: %d, shelltype: %s \n",$1,$3,$7}' /etc/passwd格式化显示/etc/passwd文件中每行的用户名,UID,shell类型,要求对应显示username,uid,shelltype,并且格式输出宽度为15个字符,左对齐。
]# awk -F: '{printf "username: %-15s, uid: %-15d, shelltype: %-15s \n",$1,$3,$7}' /etc/passwd显示/etc/fstab文件中以UUID开头的行
]# awk '/^UUID/{print }' /etc/fstab显示/etc/fstab文件中不以UUID开头的行
]# awk '!/^UUID/{print }' /etc/fstab显示UID大于500的用户名和UID
]# awk -F: '$3>=500{print $1,$3}' /etc/passwd]# awk -F: '{if($3>=500)print $1,$3}' /etc/passwd
显示shell类型为bash的用户
]# awk -F: '$NF=="/bin/bash"{print $1,$NF}' /etc/passwd]# awk -F: '$NF~/bash$/{print $1,$NF}' /etc/passwd