GNU awk
全称: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
原创文章,作者:M20-1马星,如若转载,请注明出处:http://www.178linux.com/48725