awk用法详解
一、awk介绍
awk是文本三剑客之一,其实awk是一种语言,该语言的创始者定义为”生成报表和格式化文本输出“awk有很多种版本,这里介绍的是GUN awk(gawk)
二、awk工作原理
第一步:执行BEGIN{action}语句块中的语句,该语句块不依赖于文件,awk在执行是,将在读取文件之前执行该语句中的语句块,常用语变量的初始化,打印输出表格的表头。
第二步:从文件、标准输入、上一条命令输出结果输入地区一行,然后进行pattern{aciton}语句块,它将逐行扫描文件,从第一行到最后一行。若没有提供pattern语句,则默认执行打印{print},即打印每一个读取到的行。
第三步:当读至文件最后时,执行END{action}语句块。通常用于汇总在pattern语句中执行的过程
三、awk基本用法
选项
-F"指定分隔符"
-v 自定义变量:定义变量
awk {print} file
awk将把file文件中的每一行都读取一遍,然后输出在终端上
输入内置变量在文本中代表如下图所示
[root@centos6 ~]# awk -F: -v OFS="===" -v ORS="####" '{print $1,$2}' /etc/passwd #将输出间隔符换为===将换行符换为###输出结果如下
实例一
[root@centos6 ~]#awk -F: '{print $1,$3}' /etc/passwd #表示已“ : ”为分隔符,取第一列和第三列,然后将结果输出出来
四、awk内置变量
awk命令的print打印内容也可以不与文件有关,若没有关系,则表示文件有多少行内容,就会打印自己所指定的内容,而在awk中,处理动作中的字母若不用" "引上则表示使用变量,所以若需要输出字符串则需要用“ ”引上。数字则不需要。
实例一、输入分隔符
[root@centos6 ~]#echo {1..10}
1 2 3 4 5 6 7 8 9 10
[root@centos6 ~]#echo {1..10}|awk -v FS=" " '{print $1,$3}'
这里表示原本输出结果为1到时,拿FS内置变量举例,设置空白字符为分隔符(默认分隔符就是空白字符,所以不指定结果也是一样的,这里只是为了举例说明),取1,3列,
实例二、替换输出分隔符
[root@centos6 ~]#echo {1..10} | awk -v OFS=":" '{print $1,$2,$3}'
1:2:3
1.
2.
这里OFS内置变量表示将输出结果分隔符变成:,取1,2,3列
实例三、分别显示两个文本的行号
[root@centos6 ~]#awk '{print FNR,$0}' /etc/fstab /etc/issue #表示分别显示每一个文件的行号
1
2 #
3 # /etc/fstab
4 # Created by anaconda on Fri Mar 9 08:50:54 2018
5 #
6 # Accessible filesystems, by reference, are maintained under '/dev/disk'
7 # See man pages fstab(5), findfs(8), mount(8) and/or blkid(8) for more info
8 #
9 /dev/mapper/vgentos6-LogVol03 / ext4 defaults 1 1
10 /dev/mapper/vgentos6-LogVol02 /app ext4 defaults 1 2
11 UUID=8f86cc7e-f593-467d-b823-eae6610616a1 /boot ext4 defaults 1 2
12 /dev/mapper/vgentos6-LogVol00 /var ext4 defaults 1 2
13 /dev/mapper/vgentos6-LogVol01 swap swap defaults 0 0
14 tmpfs /dev/shm tmpfs defaults 0 0
15 devpts /dev/pts devpts gid=5,mode=620 0 0
16 sysfs /sys sysfs defaults 0 0
17 proc /proc proc defaults 0 0
18 /dev/cdrom /mnt/base auto defaults 0 0
1 CentOS release 6.9 (Final)
2 Kernel \r on an \m
3
1.
2.
3.
4.
5.
6.
五、printf格式化输出
在输出内容时,print输出只能输出规定格式的内容,不能自定义格式,所以想要让输出结果根据自己所需要的格式输出就需要用printf来定制格式
printf使用格式
awk ‘{printf "格式1 格式 ",$1,$2}’,格式必须和需要输出的列一一对应
实例一、格式化输出,让文本左对齐
[root@centos6 ~]#awk -F: '{printf "%-20s %-20d\n",$1,$3}' /etc/passwd
因为printf不会自动换行,所以在规定好的格式后面增加\n来起到换行符的作用,其中-代表左对齐,若需要右对齐则直接填整数即可
六、awk运算符
awk也可以进行数字间的运算,不但支持整数,而且支持小数
实例一、两个数之间的运算
[root@centos6 ~]#awk 'BEGIN{print 5+10}'
[root@centos6 ~]#awk 'BEGIN{print 5.5+10.5}'
[root@centos6 ~]#awk 'BEGIN{print 40/3}'
七、赋值运算
在赋值操作符中,sum+=i,就相当于sum=sum+i,
实例一、将100以内的数相加
seq 100 | awk ‘{sum+=$1}END{print sum}’
5050
因为awk本来就是针对行行的循环,可以根据这个特性将1到100相加在END部分将sum值输出,就实现了100百以内数相加
实例二、变量的自增
[root@centos6 ~]#awk '{print i++}' /etc/passwd
在awk中,变量一旦与运算符号结合使用,将认为该变量的初始值为0,这个这条语句表示从零开始/etc/passwd文件有多少行,i变量将自增几次
八、模式匹配
awk模式通配符,表示左边的内容是否和右边内容匹配包含,!则表示不匹配
实例一、在文件中查找包含某字符的行
[root@centos6 ~]#awk -F: '$0 ~ /root/{print $0}' /etc/passwd
root:x:0:0:root:/root:/bin/bash
operator:x:11:0:operator:/root:/sbin/nologin
查看passwd这个文件包含root的行,并将其打印到终端
实例二、查找passwd文件中所有/bin/bash的行
[root@centos6 ~]#awk -F: '$0 ~ "/bin/bash"' /etc/passwd
因所搜内容中也包含 ” / “ 所以需要将搜索内容用双引号引起来
九、比较操作符
十、逻辑操作符
&&:表示同时满足两个条件
||:表示满足两个条件中的一个即可
!:表示取匹配结果的反值
实例一、取同时满足两个条件的结果&&
[root@centos6 ~]#awk -F: '$3>=50 && $3<=100{print $1,$3}' /etc/passwd
nobody 99
vcsa 69
postfix 89
sshd 74
实例二、去满足一个或两个条件的结果 ||
[root@centos6 ~]#awk -F: '$3>=50 || $3<=100{print $1,$3}' /etc/passwd
十一、条件表达式(三目表达式)
常用于只有两种情况下的判断,如果情况过多,将不适合使用三目表达式来选择
语法:判断条件?条件为真时执行语句:条件为假时执行语句
实例一、将系统中所有用户根据UID统计是系统用户还是普通用户
[root@centos6 ~]#awk -F: '{$3>=500?usertype="common user":usertype="system user";print usertype,$1}' /etc/passwd
#根据UID判断当前系统中所有用户是系统用户还是普通用户
十二、PATTERN模式搜索
该模式下也支持扩展正则表达式,支持模糊搜索
1.如果未指定,空模式,匹配每一行,默认搜索每一行
实例一
[root@centos6 ~]#awk '{print $0}' /etc/passwd
2./指定匹配字符/:仅处理能够模式匹配到的行需要用 / / 括起来,若匹配的行关键字中也有/则需要使用/来转译
实例一、只有满足root为行首的行才会被匹配
[root@centos6 ~]#awk '/^root/{print $0}' /etc/passwd #表示只匹配root为行首的行。
root:x:0:0:root:/root:/bin/bash
1.
2.
实例二、只要满足r…o条件的将全部匹配
[root@centos6 ~]#awk '/r..t/{print $0}' /etc/passwd
达式,若果为真才会被处理,
真:结果为非0值或非空值
假:结果为空字符串或0值
实例一、若条件为0或者空值时,则不会输出任何结果
[root@centos6 ~]#awk '0{print}' /etc/passwd
实例二、若条件为非0或控制时,则打印结果
[root@centos6 ~]#awk '1{print}' /etc/passwd
实例三、该表达式中,因为awk自带行间的循环,又因为非空为1,当第一次非空则将赋值1给i则有结果输出,第二次则将一个非1则为0,将0赋给i则第二个不输出,依次类推则输出结果如下
[root@centos6 ~]#seq 10 | awk 'i=!i'
4.行范围,awk也能取匹配字符的行范围 /匹配字符1/,/匹配字符2/处理动作
[root@centos6 ~]# awk '/^h/,/^f/' /etc/passwd
当遇到以h为行首的行,则打印,到行首为f结束,因为打印完之后有碰到h为行首,则继续打印,因为后面没有h为行首,则一直打印到就结束
5.BEGIN/END模式
BEGIN{}:仅在开始处理文本之前执行一次
BEGIN属于在文本执行前执行的语句块,它不依赖于任何文件或输出结果
[root@centos6 ~]#awk 'BEGIN{print "test"}'
test
1.
2.
END{}:仅在文本处理完成之后执行一次
END工作在awk处理完文本之后执行一次。可以用于打印pattern语句块执行过程的结果
它也依赖于文件或输出结果
[root@centos6 ~]#awk 'END{print "test"}' /etc/passwd
test
1.
2.
十三、awk控制语句
1.if else
语法
if(判断条件){满足条件执行的语句} [else {不满足条件执行语句}
if(判断条件1){满足条件1执行语句}else if (判断条件2{满足条件2时执行语句}else{不
满足上述两个条件执行语句]
1.
2.
3.
实例一、根据UID判断系统中用户是系统用户还是普通用户
[root@centos6 ~]#awk -F: '{if($3<=200){name="system"}else {name="user"} print $1,name}' /etc/passwd
实例二、将20到30的数相加
[root@centos6 ~]#seq 50 |awk '{if($1>=20&&$1<=30){sum+=$1}}END{print sum}'
275
1.
2.
判断系统中小于300的全部都是系统用户,其他的全部为普通用户
2.while循环
语法
{while (判断条件){循环语句}},条件为真时,开始执行循环
awk属于行之间的循环,他不会对列进行循环,所以若需要对列进行计算和格式化处理,则需要使用awk内置循环来进行
实例一、将每一行的和输出值终端
[root@centos6 ~]#cat test.txt
1 2 3 4 5 6 7 8 9 10
11 12 13 14 15 16 17 18 19 20
[root@centos6 ~]#awk '{sum=0;i=1;while(i<=NF){sum+=$i ;i++}print sum}' test.txt
55
155
1.
2.
3.
4.
5.
6.
实例二、统计/boot/grub2/grub.conf文件中行首为linux16行每一个字段的字符数
[root@centos7 ~]# awk '/^[[:space:]]+linux/{i=1;while(i<=NF){print $i,length($i);i++}}' /boot/grub2/grub.cfg
i作为自增项,循环条件为i<=字段数,length($i)内置函数,用于测量字段的长度
3.do while
语法
do{循环语句}while(判断条件),该语句与while唯一不同就是循环一定执行一次,不管判断条件是否为真
4.for循环
语法
for(变量;判断;变量自增){循环语句},其中()中必须是三部分组成
实例一、该实例和while实现的功能一直,只是写法不同
[root@centos7 ~]# awk '/^[[:space:]]+linux16/{for(i=1;i<=NF;i++){print $i,length($i)}}' /boot/grub2/grub.cfg
十三、循环控制语句
break:直接跳出循环
[root@centos6 ~]#cat test.txt
1 2 3 4 5 6 7 8 9 10
11 12 13 14 15 16 17 18 19 20
[root@centos6 ~]#awk '{for(i=1;i<=NF;i++){if($i%2==0){break}print $i}}' test.txt
因为当前文件中有两行内容,则显示两个数,如果只有一行内容,则只显示第一个数,因为当执行到2的时候跳出循环进入下次循环,而11以后则是下次循环,所以还会继续执行
continue:退出这次循环,进入下次循环、
[root@centos6 ~]#cat test.txt
1 2 3 4 5 6 7 8 9 10
11 12 13 14 15 16 17 18 19 20
[root@centos6 ~]#awk '{for(i=1;i<=NF;i++){if($i%2==0){continue}print $i}}' test.txt
1
3
5
当$i的值除以2 余数为0则跳出循环,其他则输出
next:跳出当前行循环,进入下次行循环
[root@centos6 ~]#seq 10 |awk '{if($1%2==0){next}print $1}'
next控制的是行间的调过,当该行满足这个条件,则跳出这行循环,进入下次循环
十三、awk数组
awk中的数组只有关联数组
1.可以使用任意字符串,字符串要使用双引号括起来
2.如果某数组元素实现不存在,在引用时,awk会自动创建次元素,并将其值初始化为空字符串
语法
数组名[“下标”]=“参数”
数组可以用于统计某个字符串出现过几次,用来统计次数
实例一、统计access_log文件每一个ip的访问次数
[root@centos6 ~]#awk '{ip[$1]++}END{for(i in ip){print i,ip[i]}}' access_log
十四、awk内置函数
length():返回指定字符串的长度
[root@centos6 ~]#echo abcde | awk '{print length($1)}'
5
1.
2.
rand():返回0和1之间的随机数,也就是小数在使用rand()函数时,在前面必须指定种子srand(),若想随机整数,则需要乘以一个数(根据想要的位数)
[root@centos6 ~]#awk 'BEGIN{srand();print int(rand()*10)}'
int()也是函数,它的作用是取整数,当前命令会随机取10以内的整数
sub(r,s,[t]):对t字符串进行搜索r表示模式匹配的内容,并将第一个匹配的内容替换为s
gsub(r,s,[t]):对匹配的字符全局替换
[root@centos6 ~]#echo {1..10} | awk 'gsub(" ",":",$0)'
1:2:3:4:5:6:7:8:9:10
1.
2.
将空格全局替换成:
split(s,array,[r]):以r为分隔符,切割字符串s,并且将切割后的结果保存到array的数组中,第一个索引值为1
[root@centos6 ~]#awk '{split($5,c,":")};{ip[c[1]]++}END{for (i in ip){print $1,ip[i]}}' netstat.log
十五、awk自定义函数,脚本调用
function name (虚变量1,虚变量2){
处理动作
处理动作
}
1.
2.
3.
4.
虚变量指的是需要用户输入两个变量,但是传入函数执行的变量和函数本身变量名不一致,也可以理解成一种定义格式,必须指定两个变量才可以调用该函数
awk程序也可以写成脚本,然后当程序需要是,可以直接调用执行,awk脚本也是需要执行权限,所以在执行之前需要个执行权限
脚本格式
#!/bin/awk -f
脚本内容
1.
2.
实例一
#!/bin/awk -f
function biji (x,y){
if(x>y){ max="x>y"}
else if (x==y){max="x=y"}
else{ max="x<y" }
return max
}
BEGIN{print biji(a,b)}
[root@centos6 ~]#awk -v a=7 -v b=7 -f test.awk
x=y
[root@centos6 ~]#awk -v a=7 -v b=6 -f test.awk
x>y
[root@centos6 ~]#awk -v a=5 -v b=6 -f test.awk
十六、system命令
在awk语句中,也可以根据需求调用系统的一些命令,但是要结合system内置函数来实现
语法
awk BEGIN‘system("系统命令")’