awk命令高级应用:数组、函数及控制语句

一、简介

awk命令作为一种编程语言,其用法也包括了一些高级应用如控制语句、函数及数组等。这些高级应用都让awk命令更加强大,应用更加广泛,使得其能满足更多复杂的需求。

二、awk命令的数组

awk命令也可以结合数组来完成一系列的工作,其数组格式为:array[index-expression],其中index-expression可使用任意字符串,字符串要使用双引号括起来;如果数组中的元素事先不存在,在引用时,awk命令会自动创建此元素,并将其值初始化为“空串”。

若需要对数组进行判断是否存在某个元素,可以以index in array格式进行判断确认,index会遍历数组array中的索引,如:

[root@localhost tmp]# awk -v i=mon 'BEGIN{weekdays["mon"]="monday";weekdays["tue"]="tuesday";if(i in weekdays) print weekdays[i]}'
monday

三、awk命令的函数

awk命令也支持函数的编写,通常来说用得较多的为awk命令的几个内置函数,其分别为:

rand():返回0和1之间一个随机数,单独使用rand()函数的话只会随机生成一次,后续多次执行也是生成同一批次的随机数;
srand([expr]):使用expr生成随机数,如果不指定expr,默认使用当前时间生成随机数;先执行srand(),在执行rand(),能让刷新rand()输出的随机数;
int(expr):将数值取整;
length([s]):返回指定字符串的长度;
sub(r,s,[t]):以r表示的模式来查找t所表示的字符串中匹配的内容,并将其第一次出现的匹配内容替换为s的内容;
gsub(r,s,[t]):以r表示的模式来查找t所表示的字符串中匹配的内容,并将所有的匹配内容替换为s的内容;
split(s,a[,r]):以r为分隔符切割字符串s,并将切割后的结果保存至a所表示的数组中;

awk命令也支持函数的自定义,其格式为:

function function_name(argument1,argument2,...)
{
function_body
}

上述中,function_name为用户定义的函数的名称,函数通常可以接受以逗号分割的多个arguments,参数是可选的;通常来说一个function_body是由一个或多个语句组成的。
如下例子,为定义一个函数,打印UID大于100的用户名及用户UID:

[root@localhost ~]# awk -F: 'function test(a,b){if(b>100) printf "User:%-20s UID:%-10s\n",a,b};test($1,$3)' /etc/passwd
User:avahi-autoipd        UID:170       
User:systemd-bus-proxy    UID:999       
User:systemd-network      UID:998       
User:polkitd              UID:997       
User:charlie              UID:1000    

四、awk命令的控制语句

简介中提及awk命令是一种编程语言,那么作为一种编程语言,其也有相应的控制语句。其控制语句的类型与bash shell编程的类似,包括:if-else、while、for、switch、break、continue和next。其中break、continue用于跳出循环及跳出本次循环,next用于提前结束当前行的处理,直接进入下一行。
下面重点介绍下其他的控制语句。

  • if-else
    awk命令的if-else语句通常用于对匹配的行或字段做条件判断选择,其格式通常为:

awk [options] '{if (condition) {statements} [else {statements}] }' /PATH/TO/SOMEFILE

如:
判断用户的UID,如果小于1000,则输出说明该用户为系统用户,大于或等于1000则输出说明该用户为普通用户:

[root@localhost ~]# awk -F: '{if ( $3<1000 ) { print $1,"is system user."} else {print $1,"is common user."}}' /etc/passwd
root is system user.
bin is system user.
daemon is system user.
adm is system user.
lp is system user.
sync is system user.
shutdown is system user.
halt is system user.
mail is system user.
operator is system user.
games is system user.
ftp is system user.
nobody is system user.
avahi-autoipd is system user.
systemd-bus-proxy is system user.
systemd-network is system user.
dbus is system user.
polkitd is system user.
tss is system user.
postfix is system user.
sshd is system user.
charlie is common user.
  • while循环
    awk命令的while循环常用于对一行内的多个字段进行逐个处理或者对数组中的各元素进行逐一处理。其格式为:

awk '[/PATTERN/]{while(condition) {statements}}' /PATH/TO/SOMEFILE

如:统计字段的长度:

[root@localhost ~]# awk -F: '/bash$/{i=1;while(i<=NF) {printf "%s的字段长度为:%-5s\n",$i,length($i);i++}}' /etc/passwd
root的字段长度为:4    
x的字段长度为:1    
0的字段长度为:1    
0的字段长度为:1    
root的字段长度为:4    
/root的字段长度为:5    
/bin/bash的字段长度为:9    
amandabackup的字段长度为:12   
x的字段长度为:1    
33的字段长度为:2    
6的字段长度为:1    
Amanda user的字段长度为:11   
/var/lib/amanda的字段长度为:15   
/bin/bash的字段长度为:9    
postgres的字段长度为:8    
x的字段长度为:1    
26的字段长度为:2    
26的字段长度为:2    
  • for循环
    awk命令的for 循环常用于进行累加或遍历操作,如累计某个关键字出现次数、遍历数组等等。其常见的格式为:

awk '/PATTERN/{for(变量赋值;判断条件;条件变化) {循环体}}' /PATH/TO/SOMEFILE

如打印匹配行的字段长度:

[root@localhost ~]# awk -F: '/^root/{for(i=1;i<=NF;i++) printf "The length of %s is %s\n",$i,length($i)}' /etc/passwd
The length of root is 4
The length of x is 1
The length of 0 is 1
The length of 0 is 1
The length of root is 4
The length of /root is 5
The length of /bin/bash is 9
  • switch语句

awk的switch语句类似于bashshell编程的case语句,可提供多个命令语句,当条件满足switch切换条件时,即切换运行指定的命令语句。其格式类似如下:

awk [options] '{switch(CONDITION){case [VALUE|/PATTERN/]:statement;case [VALUE|/PATTERN/]:statement;...;default:statement}}'

如下例子,打印行号为6以及5的倍数的行的行号:

[root@localhost ~]# awk -F: '{switch(NR+5){case 6:{print NR;next}; case /[[:digit:]]+0/: {print NR; next} ;default: print "-------------"}}' /etc/passwd 
1
-------------
-------------
-------------
5
-------------
-------------
-------------
-------------
-------------
-------------
-------------
-------------
-------------
15
-------------
-------------

五、使用案例

  • 次数统计
    统计当前系统中以/bin/bash为默认shell的用户个数:
[root@localhost ~]# awk -F: '{ if ($NF == "/bin/bash") {shell[$NF]++}} END{for(i in shell) {print i,shell[i]}}' /etc/passwd
/bin/bash 14

查看当前监听的端口统计:

[root@localhost ~]# netstat -tan | awk '/^tcp\>.*LISTEN.*/{split($4,port,"[:]"); count[port[2]]++} END{for (i in count) { printf "Port %s have %s listening link.\n",i,count[i]}}'
Port 53 have 1 listening link.
Port 445 have 1 listening link.
Port 139 have 1 listening link.
Port 631 have 1 listening link.
Port 22 have 1 listening link.
Port 25 have 1 listening link.
  • 查找替换
    将文件中的bash全部替换为大写的BASH后打印输出:
[root@localhost ~]# awk -F: '/.*bash$/{gsub(/bash$/,"BASH",$0);print $0}' /etc/passwd
root:x:0:0:root:/root:/bin/BASH
amandabackup:x:33:6:Amanda user:/var/lib/amanda:/bin/BASH
postgres:x:26:26:PostgreSQL Server:/var/lib/pgsql:/bin/BASH
centos:x:1001:1001::/home/centos:/bin/BASH
federo:x:1002:1002::/home/federo:/bin/BASH
counter:x:1003:1004::/home/counter:/bin/BASH
charlie:x:1004:1005::/home/charlie:/bin/BASH
Jone:x:1006:1007::/Jone:/bin/BASH
Williom:x:1200:1005::/home/Williom:/bin/BASH
mageia:x:1100:1100::/home/linux:/bin/BASH
bash:x:2003:2003::/home/bash:/bin/BASH
testbash:x:2004:2004::/home/testbash:/bin/BASH
basher:x:2005:2005::/home/basher:/bin/BASH
hadoop:x:2007:2007::/home/hadoop:/bin/BASH
  • 打印九九乘法表
[root@localhost ~]# awk 'BEGIN{for(n=1;n<=9;n++){for (i=1;i<=n;i++) printf i"x"n"="i*n" ";printf "\n"}}'
1x1=1 
1x2=2 2x2=4 
1x3=3 2x3=6 3x3=9 
1x4=4 2x4=8 3x4=12 4x4=16 
1x5=5 2x5=10 3x5=15 4x5=20 5x5=25 
1x6=6 2x6=12 3x6=18 4x6=24 5x6=30 6x6=36 
1x7=7 2x7=14 3x7=21 4x7=28 5x7=35 6x7=42 7x7=49 
1x8=8 2x8=16 3x8=24 4x8=32 5x8=40 6x8=48 7x8=56 8x8=64 
1x9=9 2x9=18 3x9=27 4x9=36 5x9=45 6x9=54 7x9=63 8x9=72 9x9=81 
  • 随机数
    生成10个随机数:
[root@localhost ~]# awk 'BEGIN{srand();for(i=1;i<=10;i++) printf "%5f\n",rand()}' | cut -d. -f2
102331
880760
844083
462001
686521
368991
974802
394346
514236
192557

统计某个网站的访问流量大小:

[root@localhost ~]# cat /var/log/httpd/access_log | awk '{sum+=$10} END{printf "%fG\n", sum/1024/1024/1024}'
0.000097G

你可能感兴趣的:(awk命令高级应用:数组、函数及控制语句)