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
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,922评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,591评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,546评论 0 350
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,467评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,553评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,580评论 1 293
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,588评论 3 414
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,334评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,780评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,092评论 2 330
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,270评论 1 344
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,925评论 5 338
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,573评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,194评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,437评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,154评论 2 366
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,127评论 2 352

推荐阅读更多精彩内容

  • awk介绍awk变量printf命令:实现格式化输出操作符awk patternawk actionawk数组aw...
    哈喽别样阅读 1,562评论 0 4
  • awk: grep,sed,awk grep:文本过滤 sed:文本编辑 awk:文本格式化工具; 1 什么是aw...
    木林森阅读 1,776评论 0 16
  • linux资料总章2.1 1.0写的不好抱歉 但是2.0已经改了很多 但是错误还是无法避免 以后资料会慢慢更新 大...
    数据革命阅读 12,156评论 2 33
  • 转载 原文的排版和内容都更加友好,并且详细,我只是在这里贴出了一部分留作自己以后参考和学习,如希望更详细了解AWK...
    XKirk阅读 3,206评论 2 25
  • awk命令的基本使用 [root@shellscript ~]# head -n 3 /etc/passwd | ...
    古寒飞阅读 1,064评论 0 2