本文共 11866 字,大约阅读时间需要 39 分钟。
awk是文本三剑客之一,其实awk是一种语言,该语言的创始者定义为”生成报表和格式化文本输出“awk有很多种版本,这里介绍的是GUN awk(gawk)
第一步:执行BEGIN{action}语句块中的语句,该语句块不依赖于文件,awk在执行是,将在读取文件之前执行该语句中的语句块,常用语变量的初始化,打印输出表格的表头。
第二步:从文件、标准输入、上一条命令输出结果输入地区一行,然后进行pattern{aciton}语句块,它将逐行扫描文件,从第一行到最后一行。若没有提供pattern语句,则默认执行打印{print},即打印每一个读取到的行。 第三步:当读至文件最后时,执行END{action}语句块。通常用于汇总在pattern语句中执行的过程选项
-F"指定分隔符"-v 自定义变量:定义变量 awk {print} fileawk将把file文件中的每一行都读取一遍,然后输出在终端上输入内置变量在文本中代表如下图所示[root@centos6 ~]#awk -F: -v OFS="===" -v ORS="####" '{print $1,$2}' /etc/passwd #将输出间隔符换为===将换行符换为###输出结果如下root===x####bin===x####daemon===x####adm===x####lp===x####sync===x####shutdown===x####halt===x####mail===x####uucp===x####operator===x####games===x####gopher===x####ftp===x####nobody===x####vcsa===x####saslauth===x####postfix===x####sshd===x####lin===x####tcpdump===x####hacker===x####dbus===x####test===x####apache===x####[root@centos6 ~]#实例一
[root@centos6 ~]#awk -F: '{print $1,$3}' /etc/passwd #表示已“ : ”为分隔符,取第一列和第三列,然后将结果输出出来root 0bin 1daemon 2adm 3lp 4sync 5shutdown 6halt 7mail 8uucp 10operator 11
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 3
这里表示原本输出结果为1到时,拿FS内置变量举例,设置空白字符为分隔符(默认分隔符就是空白字符,所以不指定结果也是一样的,这里只是为了举例说明),取1,3列,
实例二、替换输出分隔符[root@centos6 ~]#echo {1..10} | awk -v OFS=":" '{print $1,$2,$3}'1:2:3
这里OFS内置变量表示将输出结果分隔符变成:,取1,2,3列
实例三、分别显示两个文本的行号[root@centos6 ~]#awk '{print FNR,$0}' /etc/fstab /etc/issue #表示分别显示每一个文件的行号1 2 #3 # /etc/fstab4 # Created by anaconda on Fri Mar 9 08:50:54 20185 #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 info8 #9 /dev/mapper/vgentos6-LogVol03 / ext4 defaults 1 110 /dev/mapper/vgentos6-LogVol02 /app ext4 defaults 1 211 UUID=8f86cc7e-f593-467d-b823-eae6610616a1 /boot ext4 defaults 1 212 /dev/mapper/vgentos6-LogVol00 /var ext4 defaults 1 213 /dev/mapper/vgentos6-LogVol01 swap swap defaults 0 014 tmpfs /dev/shm tmpfs defaults 0 015 devpts /dev/pts devpts gid=5,mode=620 0 016 sysfs /sys sysfs defaults 0 017 proc /proc proc defaults 0 018 /dev/cdrom /mnt/base auto defaults 0 01 CentOS release 6.9 (Final)2 Kernel \r on an \m3
在输出内容时,print输出只能输出规定格式的内容,不能自定义格式,所以想要让输出结果根据自己所需要的格式输出就需要用printf来定制格式
printf使用格式awk ‘{printf "格式1 格式 ",$1,$2}’,格式必须和需要输出的列一一对应实例一、格式化输出,让文本左对齐[root@centos6 ~]#awk -F: '{printf "%-20s %-20d\n",$1,$3}' /etc/passwdroot 0 bin 1 daemon 2 adm 3 lp 4 sync 5 shutdown 6 halt 7 mail 8 uucp 10
因为printf不会自动换行,所以在规定好的格式后面增加\n来起到换行符的作用,其中-代表左对齐,若需要右对齐则直接填整数即可
awk也可以进行数字间的运算,不但支持整数,而且支持小数
实例一、两个数之间的运算[root@centos6 ~]#awk 'BEGIN{print 5+10}'15[root@centos6 ~]#awk 'BEGIN{print 5.5+10.5}'16[root@centos6 ~]#awk 'BEGIN{print 40/3}'13.3333
在赋值操作符中,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/passwd0123456789101112131415161718192021222324
在awk中,变量一旦与运算符号结合使用,将认为该变量的初始值为0,这个这条语句表示从零开始/etc/passwd文件有多少行,i变量将自增几次
awk模式通配符~,表示左边的内容是否和右边内容匹配包含,!~则表示不匹配
实例一、在文件中查找包含某字符的行[root@centos6 ~]#awk -F: '$0 ~ /root/{print $0}' /etc/passwdroot:x:0:0:root:/root:/bin/bashoperator:x:11:0:operator:/root:/sbin/nologin
查看passwd这个文件包含root的行,并将其打印到终端
实例二、查找passwd文件中所有/bin/bash的行[root@centos6 ~]#awk -F: '$0 ~ "/bin/bash"' /etc/passwdroot:x:0:0:root:/root:/bin/bashlin:x:500:500::/home/lin:/bin/bashhacker:x:501:501::/home/hacker:/bin/bashtest:x:502:502::/home/test:/bin/bash
因所搜内容中也包含 ” / “ 所以需要将搜索内容用双引号引起来
&&:表示同时满足两个条件
||:表示满足两个条件中的一个即可!:表示取匹配结果的反值实例一、取同时满足两个条件的结果&&[root@centos6 ~]#awk -F: '$3>=50 && $3<=100{print $1,$3}' /etc/passwdnobody 99vcsa 69postfix 89sshd 74tcpdump 72dbus 81
实例二、去满足一个或两个条件的结果 ||
[root@centos6 ~]#awk -F: '$3>=50 || $3<=100{print $1,$3}' /etc/passwdroot 0bin 1daemon 2adm 3lp 4sync 5shutdown 6halt 7mail 8uucp 10operator 11games 12gopher 13ftp 14nobody 99vcsa 69saslauth 499postfix 89sshd 74lin 500tcpdump 72hacker 501dbus 81test 502apache 48
常用于只有两种情况下的判断,如果情况过多,将不适合使用三目表达式来选择
语法:判断条件?条件为真时执行语句:条件为假时执行语句实例一、将系统中所有用户根据UID统计是系统用户还是普通用户[root@centos6 ~]#awk -F: '{$3>=500?usertype="common user":usertype="system user";print usertype,$1}' /etc/passwd#根据UID判断当前系统中所有用户是系统用户还是普通用户system user rootsystem user binsystem user daemonsystem user admsystem user lpsystem user syncsystem user shutdownsystem user haltsystem user mailsystem user uucpsystem user operatorsystem user gamessystem user gophersystem user ftpsystem user nobodysystem user vcsasystem user saslauthsystem user postfixsystem user sshdcommon user linsystem user tcpdumpcommon user hackersystem user dbuscommon user testsystem user apache
该模式下也支持扩展正则表达式,支持模糊搜索
1.如果未指定,空模式,匹配每一行,默认搜索每一行实例一[root@centos6 ~]#awk '{print $0}' /etc/passwdroot:x:0:0:root:/root:/bin/bashbin:x:1:1:bin:/bin:/sbin/nologindaemon:x:2:2:daemon:/sbin:/sbin/nologinadm:x:3:4:adm:/var/adm:/sbin/nologinlp:x:4:7:lp:/var/spool/lpd:/sbin/nologinsync:x:5:0:sync:/sbin:/bin/sync
2./指定匹配字符/:仅处理能够模式匹配到的行需要用 / / 括起来,若匹配的行关键字中也有/则需要使用\/来转译
实例一、只有满足root为行首的行才会被匹配[root@centos6 ~]#awk '/^root/{print $0}' /etc/passwd #表示只匹配root为行首的行。root:x:0:0:root:/root:/bin/bash
实例二、只要满足r..o条件的将全部匹配
[root@centos6 ~]#awk '/r..t/{print $0}' /etc/passwdroot:x:0:0:root:/root:/bin/bashoperator:x:11:0:operator:/root:/sbin/nologinftp:x:14:50:FTP User:/var/ftp:/sbin/nologin
3.关系表达式,若果为真才会被处理,
真:结果为非0值或非空值假:结果为空字符串或0值实例一、若条件为0或者空值时,则不会输出任何结果[root@centos6 ~]#awk '0{print}' /etc/passwd
实例二、若条件为非0或控制时,则打印结果
[root@centos6 ~]#awk '1{print}' /etc/passwdroot:x:0:0:root:/root:/bin/bashbin:x:1:1:bin:/bin:/sbin/nologindaemon:x:2:2:daemon:/sbin:/sbin/nologinadm:x:3:4:adm:/var/adm:/sbin/nologinlp:x:4:7:lp:/var/spool/lpd:/sbin/nologinsync:x:5:0:sync:/sbin:/bin/sync
实例三、该表达式中,因为awk自带行间的循环,又因为非空为1,当第一次非空则将赋值1给i则有结果输出,第二次则将一个非1则为0,将0赋给i则第二个不输出,依次类推则输出结果如下
[root@centos6 ~]#seq 10 | awk 'i=!i'13579
4.行范围,awk也能取匹配字符的行范围 /匹配字符1/,/匹配字符2/处理动作
[root@centos6 ~]# awk '/^h/,/^f/' /etc/passwdhalt:x:7:0:halt:/sbin:/sbin/haltmail:x:8:12:mail:/var/spool/mail:/sbin/nologinuucp:x:10:14:uucp:/var/spool/uucp:/sbin/nologinoperator:x:11:0:operator:/root:/sbin/nologingames:x:12:100:games:/usr/games:/sbin/nologingopher:x:13:30:gopher:/var/gopher:/sbin/nologinftp:x:14:50:FTP User:/var/ftp:/sbin/nologinhacker:x:501:501::/home/hacker:/bin/bashdbus:x:81:81:System message bus:/:/sbin/nologintest:x:502:502::/home/test:/bin/bashapache:x:48:48:Apache:/var/www:/sbin/nologin
当遇到以h为行首的行,则打印,到行首为f结束,因为打印完之后有碰到h为行首,则继续打印,因为后面没有h为行首,则一直打印到就结束
5.BEGIN/END模式
BEGIN{}:仅在开始处理文本之前执行一次BEGIN属于在文本执行前执行的语句块,它不依赖于任何文件或输出结果[root@centos6 ~]#awk 'BEGIN{print "test"}'test
END{}:仅在文本处理完成之后执行一次
END工作在awk处理完文本之后执行一次。可以用于打印pattern语句块执行过程的结果它也依赖于文件或输出结果[root@centos6 ~]#awk 'END{print "test"}' /etc/passwdtest
1.if else
语法if(判断条件){满足条件执行的语句} [else {不满足条件执行语句}if(判断条件1){满足条件1执行语句}else if (判断条件2{满足条件2时执行语句}else{不满足上述两个条件执行语句]
实例一、根据UID判断系统中用户是系统用户还是普通用户
[root@centos6 ~]#awk -F: '{if($3<=200){name="system"}else {name="user"} print $1,name}' /etc/passwdroot systembin systemdaemon systemadm systemlp systemsync systemshutdown systemhalt systemmail systemuucp systemoperator systemgames systemgopher systemftp systemnobody systemvcsa systemsaslauth userpostfix systemsshd systemlin usertcpdump systemhacker userdbus systemtest userapache system
实例二、将20到30的数相加
[root@centos6 ~]#seq 50 |awk '{if($1>=20&&$1<=30){sum+=$1}}END{print sum}'275
判断系统中小于300的全部都是系统用户,其他的全部为普通用户
2.while循环语法{while (判断条件){循环语句}},条件为真时,开始执行循环
awk属于行之间的循环,他不会对列进行循环,所以若需要对列进行计算和格式化处理,则需要使用awk内置循环来进行实例一、将每一行的和输出值终端 [root@centos6 ~]#cat test.txt 1 2 3 4 5 6 7 8 9 1011 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 55155
实例二、统计/boot/grub2/grub.conf文件中行首为linux16行每一个字段的字符数
[root@centos7 ~]# awk '/^[[:space:]]+linux/{i=1;while(i<=NF){print $i,length($i);i++}}' /boot/grub2/grub.cfg linux16 7/vmlinuz-0-rescue-e8e8f687a3b24f13bda5566ae49855e6 50root=UUID=7b231a1b-a730-40dd-ae89-4d565d07b340 46ro 2rhgb 4quiet 5net.ifnames=0 13linux16 7/vmlinuz-4.15.13.test 21root=UUID=7b231a1b-a730-40dd-ae89-4d565d07b340 46ro 2rhgb 4quiet 5net.ifnames=0 13LANG=en_US.UTF-8 16
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 linux16 7/vmlinuz-0-rescue-e8e8f687a3b24f13bda5566ae49855e6 50root=UUID=7b231a1b-a730-40dd-ae89-4d565d07b340 46ro 2rhgb 4quiet 5net.ifnames=0 13linux16 7/vmlinuz-4.15.13.test 21root=UUID=7b231a1b-a730-40dd-ae89-4d565d07b340 46ro 2rhgb 4quiet 5net.ifnames=0 13LANG=en_US.UTF-8 16
break:直接跳出循环
[root@centos6 ~]#cat test.txt 1 2 3 4 5 6 7 8 9 1011 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 111
因为当前文件中有两行内容,则显示两个数,如果只有一行内容,则只显示第一个数,因为当执行到2的时候跳出循环进入下次循环,而11以后则是下次循环,所以还会继续执行
continue:退出这次循环,进入下次循环、[root@centos6 ~]#cat test.txt 1 2 3 4 5 6 7 8 9 1011 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 135791113151719
当$i的值除以2 余数为0则跳出循环,其他则输出
next:跳出当前行循环,进入下次行循环[root@centos6 ~]#seq 10 |awk '{if($1%2==0){next}print $1}'13579
next控制的是行间的调过,当该行满足这个条件,则跳出这行循环,进入下次循环
awk中的数组只有关联数组
1.可以使用任意字符串,字符串要使用双引号括起来2.如果某数组元素实现不存在,在引用时,awk会自动创建次元素,并将其值初始化为空字符串语法数组名["下标"]="参数"数组可以用于统计某个字符串出现过几次,用来统计次数实例一、统计access_log文件每一个ip的访问次数[root@centos6 ~]#awk '{ip[$1]++}END{for(i in ip){print i,ip[i]}}' access_log 172.18.250.183 81172.18.251.149 158172.18.0.223 12172.18.251.21 81172.18.251.122 52172.18.254.6 1643172.18.253.21 74087172.18.251.150 34172.18.252.134 514
length():返回指定字符串的长度
[root@centos6 ~]#echo abcde | awk '{print length($1)}'5
rand():返回0和1之间的随机数,也就是小数在使用rand()函数时,在前面必须指定种子srand(),若想随机整数,则需要乘以一个数(根据想要的位数)
[root@centos6 ~]#awk 'BEGIN{srand();print int(rand()*10)}'
int()也是函数,它的作用是取整数,当前命令会随机取10以内的整数 sub(r,s,[t]):对t字符串进行搜索r表示模式匹配的内容,并将第一个匹配的内容替换为sgsub(r,s,[t]):对匹配的字符全局替换 [root@centos6 ~]#echo {1..10} | awk 'gsub(" ",":",$0)'1:2:3:4:5:6:7:8:9:10
将空格全局替换成:
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 tcp 13tcp 3tcp 1tcp 1tcp 1tcp 1tcp 1tcp 1tcp 1tcp 1tcp 1tcp 1tcp 1tcp 1tcp 15
function name (虚变量1,虚变量2){ 处理动作 处理动作}
虚变量指的是需要用户输入两个变量,但是传入函数执行的变量和函数本身变量名不一致,也可以理解成一种定义格式,必须指定两个变量才可以调用该函数
awk程序也可以写成脚本,然后当程序需要是,可以直接调用执行,awk脚本也是需要执行权限,所以在执行之前需要个执行权限脚本格式#!/bin/awk -f脚本内容
实例一
#!/bin/awk -ffunction biji (x,y){ if(x>y){ max="x>y"} else if (x==y){max="x=y"} else{ max="xy[root@centos6 ~]#awk -v a=5 -v b=6 -f test.awk x
在awk语句中,也可以根据需求调用系统的一些命令,但是要结合system内置函数来实现
语法awk BEGIN‘system("系统命令")’
转载于:https://blog.51cto.com/10492754/2093384