二、描述awk命令用法及示例
1、什么是gawk
gawk 是模式扫描和实现处理的语言,主要功能是实现文本格式化输出
2、基本用法:
- 格式:gawk [options] ‘program’ FILE …
- program: PATTERN{ACTION STATEMENTS}
语句之间用分号分隔
print, printf实现文本格式化输出
- 选项:
-F:指明输入时用到的字段分隔符;
-v var=value: 自定义变量;
3、print
- 格式 print item1, item2, …
示例:
root@bogon ~]# tail -5 /etc/fstab |awk ‘{print $2,$4}’ #读取fatab最后五行取第二和第四字段
swap defaults
/dev/shm defaults
/dev/pts gid=5,mode=620
/sys defaults
/proc defaults
- 要点:
(1) 逗号分隔符;
(2) 输出的各item可以字符串,也可以是数值;当前记录的字段、变量或awk的表达式;
(3) 如省略item,相当于print $0;
4、变量
内建变量
- FS:input field seperator,输入默认为空白字符;
- FS:output field seperator,输出默认为空白字符;
- RS:input record seperator,输入时的换行符;
- ORS:output record seperator,输出时的换行符;
- NF:number of field,每一行的字段数量
{print NF}, {print $NF}
- NR:number of record, 行数;
- FNR:各文件分别计数;行数;
- FILENAME:当前文件名;
- ARGC:命令行参数的个数;
- ARGV:数组,保存的是命令行所给定的各参数;
示例:
[root@bogon ~]# awk ‘{print NF}’ /etc/fstab #每一行的字段数量
0
1
2
root@bogon ~]# awk ‘{print FILENAME}’ /etc/fstab #取出文件名
/etc/fstab
/etc/fstab
5、定义变量
- (1) -v var=value
变量名区分字符大小写;
- (2) 在program中直接定义
6、printf命令
- 格式化输出:printf FORMAT, item1, item2, …
- (1) FORMAT格式符必须给出;
- (2) 不会自动换行,需要显式给出换行控制符,\n
- (3) FORMAT中需要分别为后面的每个item指定一个格式化符号;
- 格式符:
%c: 显示字符的ASCII码;
%d, %i: 显示十进制整数;
%e, %E: 科学计数法数值显示;
%f:显示为浮点数;
%g, %G:以科学计数法或浮点形式显示数值;
%s:显示字符串;
%u:无符号整数;
%%: 显示%自身;
- 修饰符:
#[.#]:第一个数字控制显示的宽度;第二个#表示小数点后的精度;
%3.1f
-: 左对齐
+:显示数值的符号
- 示例:
[root@bogon ~]# awk -F: ‘{printf “Username: %-15s, UID:%d\n”,$1,$3}’ /etc/passwd
Username: root , UID:0
Username: bin , UID:1
Username: daemon , UID:2
Username: adm , UID:3
Username: lp , UID:4
Username: sync , UID:5
7、操作符
- 算术操作符:x+y, x-y, x*y, x/y, x^y, x%y ,-x,+x: 转换为数值;
- 赋值操作符:=, +=, -=, *=, /=, %=, ^=++, –
- 比较操作符:>, >=, <, <=, !=, ==
- 模式匹配符:
- 逻辑操作符:&&,||,!
示例:判断用户id大于1000的为系统用户:
[root@bogon ~]# awk -F: ‘{$3>=1000?usertype=”Common User”:usertype=”Sysadmin or SysUser”;printf “%15s:%-s\n”,$1,usertype}’ /etc/passwd
root:Sysadmin or SysUser
bin:Sysadmin or SysUser
daemon:Sysadmin or SysUser
adm:Sysadmin or SysUser
8、PATTERN:模式
[root@bogon ~]# awk ‘/^UUID/{print $1}’ /etc/passwd
- (2) /regular expression/:仅处理能够被此处的模式匹配到的行;
- (3) relational expression: 关系表达式;结果有“真”有“假”;结果为“真”才会被处理;真:结果为非0值,非空字符串;
[root@bogon ~]# awk -F: ‘$NF~/bash$/{print $1,NF}’ /etc/passwd
root 7
- (4) line ranges:行范围,
startline,endline:/pat1/,/pat2/
[root@bogon ~]# awk -F: ‘/^r/,/^m/{print $1}’ /etc/passwd
root
bin
注意:不支持直接给出数字的格式
~]# awk -F: ‘(NR>=2&&NR<=10){print $1}’ /etc/passwd
(5) BEGIN/END模式
BEGIN{}: 仅在开始处理文件中的文本之前执行一次;
END{}:仅在文本处理完成之后执行一次;
[root@bogon ~]# awk -F: ‘BEGIN[print “username uid \n—————–“}{print $1,$3}END{print “================\n end “}’ /etc/passwd
9、控制语句
(1)if语句
格式:
- if(condition) {statments}
[root@localhost ~]# awk -F: ‘{if($3>=1000) print $1,$3}’ /etc/passwd
nfsnobody 65534
- if(condition) {statments} else {statements}
[root@localhost ~]# awk -F: ‘{if($3>=1000) {print “Common user:%s\n”,$1} else {printf “root or Sysuser:%s\n”,$1}}’ /etc/passwd
root or Sysuser: root #大于1000的为普通用户否则为系统用户
root or Sysuser: bin
root or Sysuser: daemon
- while(conditon) {statments}
- do {statements} while(condition)
- for(expr1;expr2;expr3) {statements}
- break
- continue
- delete array[index]
- delete array
- exit
(2)判断语句 if-else
- 语法:if(condition) statement [else statement]
[root@localhost ~]# awk -F: ‘{if($NF==“/bin/bash”) print $1}’ /etc/passwd
root
hadoop
bash
testbash
[root@bogon ~]# awk ‘{if(NF>5) print $0}’ /etc/fstab # 空白大于五个打印出来
[root@bogon ~]# df -h | awk -F[%] ‘/^\/dev/{print $1}’ | awk ‘{if($NF>=20) print $1}’ #df显示对应设备的使用空间比例指明以%号或空白作为分割以dev开头的条件过滤使用大于百分之20的设备打印出来
/dev/sda1
- 使用场景:对awk取得的整行或某个字段做条件判断;
(3)、 while循环
- 语法:while(condition) statement
条件“真”,进入循环;条件“假”,退出循环;
- 使用场景:对一行内的多个字段逐一类似处理时使用;对数组中的各元素逐一处理时使用;
[root@bogon ~]# awk ‘/^[[:space:]]*linux16/{i=1;while(i<=NF) {if(length($i)>=7) {print $i,length($i)}; i++}}’ /etc/grub2.cfg #以空白字符开头,可以多个的linux16的字段,如果i小于nf去打印$i,调用length传递参数计算长度如果大于7打印
(4)、do-while循环
- 语法:do statement while(condition)
意义:至少执行一次循环体
(5)、 for循环
- 语法:for(expr1;expr2;expr3) statement
- 格式:for(variable assignment;condition;iteration process) {for-body}
[root@bogon ~]# awk ‘/^[[:space:]]*linux16/{for(i=1;i<=NF;i++) {print $i,length($i)}}’ /etc/grub2.cfg
- 特殊用法:
能够遍历数组中的元素;
语法:for(var in array) {for-body}
(6) switch语句
- 语法:switch(expression) {case VALUE1 or /REGEXP/: statement; case VALUE2 or /REGEXP2/: statement; …; default: statement}
(7) break和continue
- break [n]:跳出循环
- continue:提前结束本次循环,进入下一次循环
(8) next
[root@bogon ~]# awk -F: ‘{if($3%2!=0) next; print $1,$3}‘ /etc/passwd #显示用户号为偶数的ID,如果不符合结束本行,提前进入下一行
10、array关联数组
- 关联数组:array[index-expression]
- index-expression:
(1) 可使用任意字符串;字符串要使用双引号;
(2) 如果某数组元素事先不存在,在引用时,awk会自动创建此元素,并将其值初始化为“空串”;
- 若要判断数组中是否存在某元素,要使用”index in array”格式进行;
- 用法:
- weekdays[mon]=”Monday”
- 若要遍历数组中的每个元素,要使用for循环;
- for(var in array) {for-body}
[root@localhost ~]# awk ‘BEGIN{weekdays[“mon”]=“Monday”;weekdays[“tue”]=“Tuesday”;for(i in weekdays) {print weekdays[i]}}’ #输出数组weekday里面i的值
Monday
Tuesday
- 注意:var会遍历array的每个索引;
state[“LISTEN”]++数组state
state[“ESTABLISHED”]++数组establish
[root@localhost ~]# netstat -tan | awk ‘/^tcp\>/{state[$NF]++}END{for(i in state) { print i,state[i]}}’ #以tap开头每行的最后一个字段遍历一次记录到数组state里每个相同字段+1 碰到另一个字段+1end 统计i里的数据
[root@localhost ~]# awk ‘{ip[$1]++}END{for(i in ip) {print i,ip[i]}}’ /var/log/httpd/access_log #Ip地址做下标i为索引每个ip访问多少次报告生成器
示例:统计/etc/fstab文件中每个文件系统类型出现的次数;
[root@bogon ~]# awk ‘/^UUID/{fs[$3]++}END{for(i in fs) {print i,fs[i]}}’ /etc/fstab #以UUID为开头的行fs数组以$3 做下标遍历end统计
xfs 1
示例:统计指定文件中每个单词出现的次数;
[root@bogon ~]# awk ‘{for(i=1;i<=NF;i++){count[$i]++}}END{for(i in count) {print i,count[i]}}’ /etc/fstab #做行内字段遍历每一个字段NF count数组下标$i end统计
swap 2
fstab(5), 1
filesystems, 1
2018 1
三、描述awk函数示例
- 内置函数
- 数值处理:
rand():返回0和1之间一个随机数;
[root@bogon ~]# awk ‘BEGIN{srand();fr=int(100*rand());print fr;}’ #获取一个随机数
71
- 字符串处理:
- length([s]):返回指定字符串的长度;
- sub(r,s,[t]):以r表示的模式来查找t所表示的字符中的匹配的内容,并将其第一次出现替换为s所表示的内容;
- gsub(r,s,[t]):以r表示的模式来查找t所表示的字符中的匹配的内容,并将其所有出现均替换为s所表示的内容;
[root@bogon ~]
root:x:0:0:root:/root:/bin/BASH
- split(s,a[,r]):以r为分隔符切割字符s,并将切割后的结果保存至a所表示的数组中;
示例:
[root@bogon ~]# netstat -tan | awk ‘/^tcp\>/{split($5,ip,“:”);count[ip[1]]++}END{for (i in count) {print i,count[i]}}’
192.168.1.103 1
0.0.0.0 2
# 对第五段做切割保存到ip数组中以:做分隔符对每个ip数组分别做统计显示i各自出现次数