@[TOC](第十八章 ⽂本处理三剑客之AWK)
实验⼀:awk的基本⽤法
⽬的
awk是报告生成器,格式化文本输出,有多种版本。centos中的是gawk即GNU awk版本。本次实验主要掌握awk基本用法。
awk⼯作原理:
- 第一步:执行BEGIN{action;...}语句块中的语句。
- 第二步:从文件或标准输入(stdin)读取一行,然后执行pattern{action;...}语句块,它逐行扫描文件,从第一行到最后一行重复这个过程,直到文件全部被读取完毕。
- 第三步:当读至输入流末尾时,执行END{action;...}语句块。
- BEGIN语句块在awk开始从输入流中读取行之前被执行,这是一个可选的语句块,比如变量初始化、打印输出表格的表头等语句通常可写咋BEGIN语句块中。
- END语句块在awk从输入流中读完所有的行之后被执行,比如打印所有行的分析结果这类信息汇总都是在END语句 块中完成,它也是一个可选语句块。
- pattern语句块中的通用命令是最重要的部分,也是可选的。如果没有提供pattern语句块,则默认执行{print},即打印每一个读取到的行,awk读取的每一行都会执行该语句块。
print格式:print item1, item2, ...
注意
逗号分隔符;
输出的各item可以是字符串,也可是数值;当前记录的字段、变量或awk的表达式;
如省略item,相当于print $0。
前提
可用的centos6系统,连接物理网络。
awk基本⽤法
awk [options] 'program' var=value file ...
awk [options] -f programfile var=value file ...
awk [options] 'BEGIN{ action;...} pattern{ action;... } END{ action;... }' file ...
awk程序通常由:BEGIN语句块、能够使⽤模式匹配的通⽤语句块、END语句块等三部分组成。program通常是被单引号 或双引号括起来。
选项:
-F:指明输入时用到的字段分隔符;
-v var=value:自定义变量。
基本格式:
awk [options] 'program' file
program:表示为pattern{action statements;...} pattern:表示部分决定动作语句何时触发及触发事件BEGIN、END; action statements:表示对数据进行处理,放置{}内指明print、printf。
分隔符、域和记录:
awk执行时,由分隔符的字段(域)标记2...0为所有域,注意:和shell中变量0的操作。
⽣成需要的测试数据:
[root@magedu ~]# head -10 /etc/passwd > awktest.txt
【例1】awk省略action,默认执⾏print $0
[root@magedu ~]# awk '{print}' awktest.txt
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
adm:x:3:4:adm:/var/adm:/sbin/nologin
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
sync:x:5:0:sync:/sbin:/bin/sync
shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
halt:x:7:0:halt:/sbin:/sbin/halt
mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
uucp:x:10:14:uucp:/var/spool/uucp:/sbin/nologin
【例2】指定:(冒号)为分隔符,打印每⾏记录的第⼀个字段即输出$1
[root@magedu ~]# awk -F: '{print $1}' awktest.txt
root
bin
daemon
adm
lp
sync
shutdown
halt
mail
uucp
同理再把第三个字段输出,输出前添加三个连字符(---):
[root@magedu ~]# awk -F: '{print $1"---"$3}' awktest.txt
root---0
bin---1
daemon---2
adm---3
lp---4
sync---5
shutdown---6
halt---7
mail---8
uucp---1
【例3】取出磁盘使⽤率
[root@localhost ~]# df |grep "^/dev"|awk '{print $5}'
24%
19%
100%
【例4】BEGIN的使⽤:
[root@magedu ~]# awk '{print 2.5*3}' awktest.txt
7.5
7.5
7.5
7.5
7.5
7.5
7.5
7.5
7.5
7.5
[root@magedu ~]# awk 'BEGIN{print 2.5*3}' awktest.txt
7.5
[root@magedu ~]# awk 'BEGIN{print 2.5*3}'
7.5
实验⼆:awk的变量⽤法
目的
掌握awk内置变量和自定义变量的用法。
内置变量:
FS:输入自动分隔符,默认为空白字符;
OFS:输出自动分隔符,默认为空白字符; RS:输入记录分隔符,指定输入时的换行符,原换行符仍有效;
ORS:输出记录分隔符,输出时用指定符号代替换行符; NF:字段数量; NR:行号; FNR:各文件分别计数,记录号; FILENAME:当前文件名;
ARGC:命令行参数的个数; ARGV:数组,保存的是命令行所给定的各参数。
前提
可用的centos6系统。
1、awk的内建变量使⽤
【例1】输⼊字段分隔符FS变量的使⽤
[root@magedu ~]# awk -v FS=':' '{print $1,FS,$3}' awktest.txt
root : 0
bin : 1
daemon : 2
adm : 3
lp : 4
sync : 5
shutdown : 6
halt : 7
mail : 8
uucp : 10
【例2】输⼊出字段分隔符OFS变量的使⽤
[root@magedu ~]# awk -v FS=':' -v OFS='----' '{print $1,$3,$7}' awktest.txt
root----0----/bin/bash
bin----1----/sbin/nologin
daemon----2----/sbin/nologin
adm----3----/sbin/nologin
lp----4----/sbin/nologin
sync----5----/bin/sync
shutdown----6----/sbin/shutdown
halt----7----/sbin/halt
mail----8----/sbin/nologin
uucp----10----/sbin/nologin
【例3】输⼊记录分隔符RS变量的使⽤
[root@magedu ~]# head -1 awktest.txt | awk -v RS=':' '{print}'
root
x00
root
/root
/bin/bash
【例4】输出记录分隔符ORS变量的使⽤
[root@magedu ~]# awk -v OR=' ' -v ORS='----' '{print}' awktest.txt
root:x:0:0:root:/root:/bin/bash----bin:x:1:1:bin:/bin:/sbin/nologin----
daemon:x:2:2:daemon:/sbin:/sbin/nologin----adm:x:3:4:adm:/var/adm:/sbin/nologin----
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin----sync:x:5:0:sync:/sbin:/bin/sync----
shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown----halt:x:7:0:halt:/sbin:/sbin/halt----
mail:x:8:12:mail:/var/spool/mail:/sbin/nologin----
uucp:x:10:14:uucp:/var/spool/uucp:/sbin/nologin----[root@magedu ~]#
【例5】字段数量NF变量的使⽤
[root@magedu ~]# awk -F: '{print NF}' awktest.txt
7
7
7
7
7
7
7
7
7
7
[root@magedu ~]# awk -F: '{print $(NF-1)}' awktest.txt
/root
/bin
/sbin
/var/adm
/var/spool/lpd
/sbin
/sbin
/sbin
/var/spool/mail
/var/spool/uucp
【例6】⾏号NR变量的使⽤
[root@magedu ~]# awk -F: '{print NR,$1}' awktest.txt
1 root
2 bin
3 daemon
4 adm
5 lp
6 sync
7 shutdown
8 halt
9 mail
10 uucp
[root@magedu ~]# awk END'{print NR}' awktest.txt
10
【例7】各⽂件分别的记录号FNR变量的使⽤
[root@magedu ~]# awk '{print FNR,$1}' /etc/fstab /root/awktest.txt
1 UUID=0c239cec-c2f7-49b6-9090-c1adf0f074cb
2 /dev/mapper/vg_magedu-lv_root
3 /dev/mapper/vg_magedu-lv_swap
1 root:x:0:0:root:/root:/bin/bash
2 bin:x:1:1:bin:/bin:/sbin/nologin
3 daemon:x:2:2:daemon:/sbin:/sbin/nologin
4 adm:x:3:4:adm:/var/adm:/sbin/nologin
5 lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
6 sync:x:5:0:sync:/sbin:/bin/sync
7 shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
8 halt:x:7:0:halt:/sbin:/sbin/halt
9 mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
10 uucp:x:10:14:uucp:/var/spool/uucp:/sbin/nologin
【例8】当前⽂件名FILENAME变量的使⽤
[root@magedu ~]# awk '{print FILENAME,FNR,$1}' /etc/fstab /root/awktest.txt
/etc/fstab 1 UUID=0c239cec-c2f7-49b6-9090-c1adf0f074cb
/etc/fstab 2 /dev/mapper/vg_magedu-lv_root
/etc/fstab 3 /dev/mapper/vg_magedu-lv_swap
/root/awktest.txt 1 root:x:0:0:root:/root:/bin/bash
/root/awktest.txt 2 bin:x:1:1:bin:/bin:/sbin/nologin
/root/awktest.txt 3 daemon:x:2:2:daemon:/sbin:/sbin/nologin
/root/awktest.txt 4 adm:x:3:4:adm:/var/adm:/sbin/nologin
/root/awktest.txt 5 lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
/root/awktest.txt 6 sync:x:5:0:sync:/sbin:/bin/sync
/root/awktest.txt 7 shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
/root/awktest.txt 8 halt:x:7:0:halt:/sbin:/sbin/halt
/root/awktest.txt 9 mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
/root/awktest.txt 10 uucp:x:10:14:uucp:/var/spool/uucp:/sbin/nologin
【例9】命令⾏参数的个数ARGC变量的使⽤
[root@magedu ~]# awk 'BEGIN {print ARGC}' /etc/fstab /etc/inittab
3
【例10】命令⾏给定的各参数的数组ARGV变量的使⽤
[root@magedu ~]# awk 'BEGIN {print ARGV[1]}' /etc/fstab /etc/inittab
/etc/fstab
[root@magedu ~]# awk 'BEGIN {print ARGV[2]}' /etc/fstab /etc/inittab
/etc/inittab
[root@magedu ~]# awk 'BEGIN {print ARGV[0]}' /etc/fstab /etc/inittab
awk
2、awk的⾃定义变量使⽤
【例11】命令⾏给定的各参数的数组ARGV变量的使⽤[root@magedu ~]# awk -F: -v name='username:' '{print name,$1}' awktest.txt
username: root
username: bin
username: daemon
username: adm
username: lp
username: sync
username: shutdown
username: halt
username: mail
username: uucp
或变量定义在program⾥⾯为:
[root@magedu ~]# awk -F: '{name="username:"; print name,$1}' awktest.txt
或在shell中定义了变量,在awk中⾃定义的变量调⽤shell中的变量:
[root@magedu ~]# username="username"; awk -F: -v name=$username: '{print name,$1}' awktest.txt
【例12】把awk执⾏命令放⼊⼀个⽂件中,直接调⽤awk脚本⽂件
[root@magedu ~]# echo '{name="magedu";age=20;print name,$1,age}' > awkscript
[root@magedu ~]# awk -F: -f awkscript awktest.txt
magedu root 20
magedu bin 20
magedu daemon 20
magedu adm 20
magedu lp 20
magedu sync 20
magedu shutdown 20
magedu halt 20
magedu mail 20
magedu uucp 20
实验三:awk的格式化输出
目的
掌握awk中printf命令。
格式输出:printf "FORMAT", item1, item2,...
必须知道FORMAT; 不会自动换行,需要显示给出换行控制符,\n;
FORMAT中需要分别为后面每个item指定格式符。
格式符:与item⼀⼀对应
%c:显示字符的ASCII码;
%d,%i:显示十进制整数;
%e,%E:显示科学计数法数值;
%f:显示为浮点数; %g,%G:以科学计数法或浮点形式显示数值;
%s:显示字符串;
%u:无符号整数;
%%:显示%自身。
修饰符:
#[.#]:第一个#为数字控制显示的宽度,第二个#表示小数点后的精度,如%3.1f; -:左对齐(默认右对齐),如%-15s; +:显示数值的正负号,如%+d。
前提
可用的centos6系统。
1、printf命令:格式化输出
【例1】格式化输出,以冒号为分隔符,第⼀个字段宽度20个字符串,第⼆个字段宽度10个数⼦,⼀⾏输出2个字段,然后换⾏[root@magedu ~]# awk -F: '{printf "%20s %10d\n", $1,$3}' awktest.txt
root 0
bin 1
daemon 2
adm 3
lp 4
sync 5
shutdown 6
halt 7
mail 8
uucp 10
注意:输出默认是右对齐。
【例2】接上例,格式化输出为左对齐
[root@magedu ~]# awk -F: '{printf "%-20s %10d\n",$1,$3}' awktest.txt
root 0
bin 1
daemon 2
adm 3
lp 4
sync 5
shutdown 6
halt 7
mail 8
uucp 10
【例3】以冒号为分隔符,每⾏输出”username:第⼀个字段“,然后换⾏
[root@magedu ~]# awk -F: '{printf "username:%s\n",$1}' awktest.txt
username:root
username:bin
username:daemon
username:adm
username:lp
username:sync
username:shutdown
username:halt
username:mail
username:uucp
【例4】以冒号为分隔符,每⾏输出”username:第⼀个字段,左对齐,占20个宽度,UID:第三个字段“,然后换⾏
[root@magedu ~]# awk -F: '{printf "username:%-20s uid:%d\n",$1,$3}' awktest.txt
username:root uid:0
username:bin uid:1
username:daemon uid:2
username:adm uid:3
username:lp uid:4
username:sync uid:5
username:shutdown uid:6
username:halt uid:7
username:mail uid:8
username:uucp uid:10
实验四:awk的操作符
目的
掌握awk中使用操作符。
算术操作符:
x+y:加法; x-y:减法;
x*y:乘法;
x/y:除法;
x^y:幂运算;
x%y:取模(余数)。
字符串操作符:没有操作符,字符串连接。
赋值操作符:
=:右边赋值给左边;
+=:先加,再赋值;
-=:先减,再赋值;
*=:先乘,再赋值; /=:先除,再赋值; %=:先取余,再赋值;
^=:先幂运算,再赋值; ++:递增操作; --:递减操作。
⽐较操作符:
==:判断相等;
!=:判断不等;
>:判断大于;
>=:判断大于等于;
<:判断小于;
<=:判断小于等于。
模式匹配符:
:左边是否和右边匹配包含; !:是否不匹配。
awk PATTERN:awk的模式
PATTERN:根据pattern条件,过滤匹配的行,再做处理:
- 如果未指定:空模式,匹配每一行;
- /regular expression/:仅处理能够模式匹配到的行,需要用//扩起来;
- relational expression:关系表达式,结果为真,才会被处理;
- 真:结果为非0值,非空字符串都是真;
- 假:结果为空字符串或0值都是假。
- line ranges:行范围; startine,endline:/pat1/,/pat2/不支持直接给出数子格式。
- BEGIN/END模式
- BEGIN{}:仅在开始处理文件中的文本之前执行一次;
- END{}:仅在文本处理完成之后执行一次。
awk的action:常⽤的action分类
- Expression:算术,比较表达式等;
- Control statuments:if,while等;
- conmpound statements:组合语句;
- input statements:
- output statements:print等。
前提
可用的centos6系统。
逻辑操作符:
&&:逻辑与;
||:逻辑或;
!:逻辑非。
函数调⽤:
funciton_name(argu1,argu2,...)
实验步骤
1、awk使⽤算术操作符
【例1】使⽤awk的算术操作符,计算2*3[root@magedu ~]# awk 'BEGIN {print 2*3}'
6
【例2】使⽤awk的算术操作符,取模5%2
[root@magedu ~]# awk 'BEGIN {print 5%2}'
1
2、awk赋值操作符
【例3】使⽤awk的+=赋值操作符[root@magedu ~]# awk 'BEGIN{i=10;print i+=1}'
11
【例4】使⽤awk的i++赋值操作符
[root@magedu ~]# awk 'BEGIN{i=10;print i++}'
10
【例5】使⽤awk的++i赋值操作符
[root@magedu ~]# awk 'BEGIN{i=10;print ++i}'
11
[root@magedu ~]# awk 'BEGIN{i=10;print ++i;print i}'
11
11
[root@magedu ~]# awk 'BEGIN{i=10;print ++i,i}'
11 11
3、awk中的模式匹配符
【例6】匹配包含root⾏的记录[root@magedu ~]# awk -F: '$0 ~ /root/{print $0}' awktest.txt
root:x:0:0:root:/root:/bin/bash
【例7】匹配不包含root⾏的记录
[root@magedu ~]# awk -F: '$0 !~ /root/{print $0}' awktest.txt
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
adm:x:3:4:adm:/var/adm:/sbin/nologin
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
sync:x:5:0:sync:/sbin:/bin/sync
shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
halt:x:7:0:halt:/sbin:/sbin/halt
mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
uucp:x:10:14:uucp:/var/spool/uucp:/sbin/nologin
【例8】⽤正则表达式匹配包含root⾏的记录
[root@magedu ~]# awk -F: '$0 ~ /^root/{print $0}' awktest.txt
root:x:0:0:root:/root:/bin/bash
【例9】显⽰硬盘分区的使⽤率
[root@magedu ~]# df -h | awk '$0 ~ /^\/dev\/sd/{print $1,$5}'
/dev/sda1 8%
【例10】从hostname.txt⽂件中,提取域名的第⼀部分
[root@magedu ~]# cat hostname.txt
1 magedu.com.con
2 www.magedu.com
3 mail.magedu.com
[root@magedu ~]# awk -F'[.| ]' '{print $(NF-2)}' hostname.txt
magedu
www
mail
4、awk的逻辑操作符
【例11】显⽰第三字段⼤于等于0,且⼩于等于1000的⾏中的第1字段[root@magedu ~]# awk -F: '$3>=0 && $3<=1000{print $1}' awktest.txt
root
bin
daemon
adm
lp
sync
shutdown
halt
mail
uucp
【例12】显⽰第三字段等于0,或⼤于等于1000的⾏中的第1字段
[root@magedu ~]# awk -F: '$3==0 || $3>=1000{print $1}' awktest.txt
root
【例13】显⽰除了第三段等于0的⾏中的第1字段
[root@magedu ~]# awk -F: '!($3==0){print $1}' awktest.txt
bin
daemon
adm
lp
sync
shutdown
halt
mail
uucp
【例14】awk实现打印奇数⾏和偶数⾏
[root@magedu ~]# seq 10|awk '!(i=!i)'
2
4
6
8
10
[root@magedu ~]# seq 10|awk 'i=!i'
1
3
5
7
9
等同于sed命令:
[root@magedu ~]# seq 10 | sed -n '1~2p'
1
3
5
7
9
[root@magedu ~]# seq 10 | sed -n '2~2p'
2
4
6
8
10
5、awk的PATTERN使⽤
【例15】查找/etc/passwd⽂件中,以r开头的⾏,显⽰第1字段和第3字段[root@magedu ~]# awk -F: '/^r/{print $1,$3}' /etc/passwd
root 0
rpc 32
rtkit 499
rpcuser 29
【例16】查找netstat -nt命令的结果中Foreign Address列的地址,并显⽰
[root@magedu ~]# netstat -nt |awk '/^tcp/{print $5}'|awk -F: '{print $1}'
172.18.116.232
【例17】查找netstat -nt命令的结果中Foreign Address列的地址,统计每个地址链接的次数
[root@magedu ~]# netstat -nt |awk '/^tcp/{print $5}'|awk -F: '{print $1}'|sort |uniq -c
2 172.18.116.232
【例18】匹配以f开头的⾏开始,到r开头的⾏结束之间的所有⾏
[root@magedu ~]# awk '/^f/,/^r/' /etc/passwd
ftp:x:14:50:FTP User:/var/ftp:/sbin/nologin
nobody:x:99:99:Nobody:/:/sbin/nologin
dbus:x:81:81:System message bus:/:/sbin/nologin
usbmuxd:x:113:113:usbmuxd user:/:/sbin/nologin
rpc:x:32:32:Rpcbind Daemon:/var/lib/rpcbind:/sbin/nologin
注意:如果没有⼀r开头的⾏,则会从匹配的以f开头的⾏开始,到最后都显⽰。
6、BRGIN/END模式
【例19】awk的BEGIN/END模式的使⽤[root@magedu ~]# awk -F: 'BEGIN{print "user id\n**********************"} {printf "%-10s| %10d\n", $1,$3}END{print "**********************\n over"}' awktest.txt
user id
**********************
root | 0
bin | 1
daemon | 2
adm | 3
lp | 4
sync | 5
shutdown | 6
halt | 7
mail | 8
uucp | 10
**********************
over
实验五:awk的条件判断
⽬的
掌握awk的条件判断。 条件表达式:(三目表达式) selector?if-true-expression:if-false-expression
控制语句:
{statements;...}:组合语句;
if(condition){statements;...}else {statements;...}
if(condition1){statement1}else if(condition2){statement2}
else{statement3}
while(condition){statements;...}
do {statements;...} while(condition)
for(expr1;expr2;expr3) {statements;...}
break
continue
delete array[index]
delete array
exit
前提
可用的centos6系统。
哈
实验步骤
1、awk条件表达式的使⽤
【例1】显⽰uid⼤于等于500,输出common user,⽤户名和uid,否则输出sysuser[root@magedu ~]# awk -F: '{$3>=500?usertype="common user":usertype="sysuser";printf "%-15s %-20s %10d\n",usertype,$1,$3}' /etc/passwd
sysuser root 0
...
sysuser sshd 74
sysuser tcpdump 72
common user wang 500
【例2】查找netstat -nt命令的结果中Foreign Address列的地址,统计每个地址链接的次数,如果⼤于2次,显⽰ip
#如果没有结果、可以ssh再打开一个窗口
[root@magedu ~]# netstat -nt |awk '/^tcp/{print $5}'|awk -F: '{print $1}'|sort |uniq -c|awk '$1>1{print $2}'
172.18.116.232
【例3】模拟并发访问http服务,查找ip连接次数超过200次的访问ip地址 模拟并发:
[root@magedu ~]# yum -y install httpd-tools httpd
[root@magedu ~]# /etc/init.d/httpd start
[root@magedu ~]# ab -c 10 -n 200 http://172.18.120.26/
This is ApacheBench, Version 2.3 <$Revision: 655654 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/
Benchmarking 172.18.120.26 (be patient)
Completed 100 requests
Completed 200 requests
Finished 200 requests
Server Software: Apache/2.2.15
Server Hostname: 172.18.120.26
Server Port: 80
Document Path: /
Document Length: 4961 bytes
Concurrency Level: 10
Time taken for tests: 0.051 seconds
Complete requests: 200
Failed requests: 0
Write errors: 0
Non-2xx responses: 207
Total transferred: 1067913 bytes
HTML transferred: 1026927 bytes
Requests per second: 3942.44 [#/sec] (mean)
Time per request: 2.536 [ms] (mean)
Time per request: 0.254 [ms] (mean, across all concurrent requests)
Transfer rate: 20557.54 [Kbytes/sec] received
Connection Times (ms)
min mean[+/-sd] median max
Connect: 0 1 0.4 1 2
Processing: 1 1 0.4 1 3
Waiting: 0 1 0.4 1 3
Total: 1 2 0.5 2 5
Percentage of the requests served within a certain time (ms)
50% 2
66% 2
75% 2
80% 2
90% 3
95% 3
98% 4
99% 5
100% 5 (longest request)
显⽰超过200次访问的ip:
[root@magedu ~]# awk '{print $1}' /var/log/httpd/access_log|sort|uniq -c
3 172.18.116.232
207 172.18.120.26
[root@magedu ~]# awk '{print $1}' /var/log/httpd/access_log|sort|uniq -c|awk '$1>200{print
$2}'
172.18.120.26
【例4】显⽰第10条到第20条记录的第1字段
[root@magedu ~]# awk -F: '(NR>=10 && NR<=20){print NR,$1}' /etc/passwd
10 uucp
11 operator
12 games
13 gopher
14 ftp
15 nobody
16 dbus
17 usbmuxd
18 rpc
19 rtkit
20 avahi-autoipd
注意:显⽰从第10⾏到第20⾏内容,也可⽤sed命令实现:
[root@magedu ~]# sed -n '10,20p' /etc/passwd
2、awk组合语句
【例5】以冒号为分隔符,分别打印第1字段和第3字段[root@magedu ~]# awk -F: '{print $1;print $3}' awktest.txt
root
0
bin
1
daemon
2
adm
3
lp
4
sync
5
shutdown
6
halt
7
mail
8
uucp
10
3、if-else语句:对awk取得的整⾏或某字段做条件判断
【例6】对第3字段判断⼤于等于500,则显⽰每⾏的[root@magedu ~]# awk -F: '{if($3>=500)print $1,$3}' /etc/passwd
nfsnobody 65534
llj 500
li 501
zhang 502
python 503
【例7】查找最后⼀个字段是/bin/bash的⾏,打印第⼀个字段
[root@magedu ~]# awk -F: '{if($NF=="/bin/bash") print $1}' /etc/passwd
root
llj
li
zhang
python
【例8】查找以空格为分隔符,显⽰每⾏⼤于5个字段所在的⾏
[root@magedu ~]# awk '{if(NF>5) print $0}' /etc/fstab
UUID=0c239cec-c2f7-49b6-9090-c1adf0f074cb /boot ext4 defaults 0 2
/dev/mapper/vg_magedu-lv_root / ext4 defaults 0 1
/dev/mapper/vg_magedu-lv_swap swap swap defaults 0 0
【例9】查找第3字段⼤于等500,则输出Common user:第1字段,否则输出root or Sysuer:第1字段
[root@magedu ~]# awk -F: '{if($3>=500){printf "Common usre:%s\n",$1} else {printf "root or Sysuser:%s\n",$1}}' /etc/passwd
...
root or Sysuser:sshd
root or Sysuser:tcpdump
Common user:llj
Common user:li
...
或:
[root@magedu ~]# awk -F: '{if($3>=500)printf "Common user:%s\n",$1;else printf "root or Sysuser:$s\n",$1}' /etc/passwd
...
root or Sysuser:sshd
root or Sysuser:tcpdump
Common user:llj
Common user:li
...
【例10】显⽰磁盘使⽤率⼤于等于8%的分区
[root@magedu ~]# df -h | awk -F% '/^\/dev/{print $1}'|awk '$NF>=5{print $1,$5}'
/dev/sda1 8
【例11】判断awk⾃定义变量test的值,⼤于90则显⽰very good,⼤于60则显⽰good,其它值显⽰no pass
[root@centos6 ~]$ awk 'BEGIN{test=100;if(test>90){print "very good"}else if(test>60){print "good"}else{print "no pass"}}'
very good
[root@centos6 ~]$ awk 'BEGIN{test=80;if(test>90){print "very good"}else if(test>60){print "good"}else{print "no pass"}}'
good
[root@centos6 ~]$ awk 'BEGIN{test=10;if(test>90){print "very good"}else if(test>60){print "good"}else{print "no pass"}}'
no pass
实验六:awk的循环
⽬的
掌握awk的循环。 while(condition){statement;...} 条件为真,进入循环,条件为假退出循环;
使⽤场景:对⼀⾏内的多个字段逐⼀类似处理时使⽤;对数组中的各元素逐⼀处理时使⽤。
do-while循环语法:do {statement;...}while(condition)无论真假,至少执行一次循环体。
for循环语法:for(expr1;expr2;expr3){statement;...}
常见用法:
for(variable assignment;condition;iteration process
{for-body}
特殊用法:
能够遍历数组中的元素:for(var in array){for-body}
witch语句:
语法:switch(expresssion){case VALUE1 or /REGEXP/:statement1;case VALUE2 or /REGEXP2/:statement2;...;default:statement}
break、continue、next语句:
break [n]:结束整个循环默认是最近的一次循环;
continue [n]:跳过本轮循环,执行下一轮循环; next:提前结束对本行处理而直接进入下一行处理(awk自身循环)。
前提
可用的centos6系统。
实验步骤
1、awk中使⽤while循环
【例1】统计第5⾏内容中每个单词分别有多少个字符[root@magedu ~]# sed -n '5p' /etc/grub.conf
kernel /vmlinuz ro root=/dev/mapper/vg_magedu-lv_root rhgb quiet
[root@magedu ~]# awk '/kernel/{i=1;while(i<=NF){print $i,length($i);++i}}' /etc/grub.conf
kernel 6
/vmlinuz 8
ro 2
root=/dev/mapper/vg_magedu-lv_root 34
rhgb 4
quiet 5
【例2】查找最⼤数和最⼩数
[root@magedu ~]# cat num.txt
0,5,111,34,6,9,255,192,172,16
[root@magedu ~]# awk -F, '{min=$1;max=$1;i=1;while(i<=NF) {if(max<$i)max=$i;if(min>$i)min=$i;i++};print "max:"max,"min:"min}' num.txt
max:255 min:0
或使⽤shell命令实现:
[root@magedu ~]# for i in `tr ',' ' ' <num.txt`;do echo $i;done|sort -n|head
0
5
6
9
16
34
111
172
192
255
[root@magedu ~]# for i in `tr ',' ' ' <num.txt`; do echo $i;done |sort -n|tail -1
255
[root@magedu ~]# for i in `tr ',' ' ' <num.txt`; do echo $i;done |sort -n|head -1
0
【例3】计算1+2+3+...+100的和
[root@magedu ~]# awk 'BEGIN{i=1;sum=0;while(i<=100){sum+=i;i++};print "sum="sum}'
sum=5050
或使⽤shell命令实现:
[root@magedu ~]# sum=0;for i in {1..100};do let sum+=i;done;echo sum=$sum
sum=5050
【例4】awk中使⽤while循环计算10000内的总和
[root@magedu ~]#awk 'BEGIN{i=1;sum=0;while(i<=100000){sum+=i;i++};print"sum="sum}'
sum=5000050000
2、awk中使⽤do-while循环
【例5】使⽤do-while计算100000内的和[root@magedu ~]# awk 'BEGIN{total=0;i=0;do{total+=i;i++;}while(i<=100000);print total}'
5000050000
3、awk中使⽤for循环
【例6】计算100内整数的和[root@magedu ~]# awk 'BEGIN{sum=0;for(i=1;i<=100;i++){sum+=i};print sum}'
5050
4、性能⽐较
【例7】分别使⽤awk的while循环、shell的for循环等计算100000内的整数和,测试执⾏时间[root@magedu ~]#time (awk 'BEGIN{total=0;i=0;do{total+=i;i++;}while(i<=10000);print total}')
50005000
real 0m0.002s
user 0m0.000s
sys 0m0.001s
[root@magedu ~]# time ( sum=0;for i in {1..100000};do let sum+=i;done;echo sum=$sum )
sum=5000050000
real 0m0.727s
user 0m0.570s
sys 0m0.157s
[root@magedu ~]# time ( seq -s "+" 100000|bc )
5000050000
real 0m0.107s
user 0m0.102s
sys 0m0.002s
[root@magedu ~]# time(for((i=0;i<=100000;i++));do let total+=i;done;echo $total)
5000050000
real 0m0.959s
user 0m0.928s
sys 0m0.030s
5、continue语句
【例8】计算100内的奇数和[root@magedu ~]# awk 'BEGIN{sum=0;for(i=1;i<=100;i++){if(i%2==0)continue;sum+=i}print sum}'
2550
【例9】计算100内偶数和
[root@magedu ~]# awk 'BEGIN{sum=0;for(i=1;i<=100;i++){if(i%2!=0)continue;sum+=i}print sum}'
2550
6、break语句
【例10】计算100内的整数和,但遇到整数66就不计算了,退出执⾏[root@magedu ~]# awk 'BEGIN{sum=0;for(i=1;i<=100;i++){if(i==66)break;sum+=i}print sum}'
2145
7、next语句
【例11】显⽰uid为偶数⾏的第1字段和第3字段[root@magedu ~]# awk -F: '{if($3%2!=0)next;print $1,$3}' awktest.txt
root 0
daemon 2
lp 4
shutdown 6
mail 8
uucp 10
实验七:awk的数组
⽬的
掌握awk中的数组。
- 关联数组:array[index-expression]
- index-expression:
- 可使用任意字符串;字符串要使用双引号括起来
- 如果某数组元素事先不存在,在引用时,awk会自动创建此元素,并将其值初始化为空串
- 若要判断数组中是否存在某元素,要使用index in array格式进行遍历
- 若要遍历数组中的每个元素,要使用for循环
- for(var in array){for-body}
- 注意:var会遍历array的每个索引
前提
可用的centos6系统。
实验步骤
1、awk中数组
【例1】创建⼀个weekdays数组,显⽰索引为mon的数组的中的值[root@magedu ~]# awk 'BEGIN{weekdays["mon"]="Monday";weekdays["tue"]="Tuesday";print weekdays["mon"]}'
Monday
【例2】使⽤awk中数组去重
[root@magedu ~]# cat abc.txt
a
b
c
aa
bb
cc
a
b
c
[root@magedu ~]# awk '!arr[$0]++' abc.txt
a
b
c
aa
bb
cc
【例3】去重的思路演⽰
[root@magedu ~]# awk '{!arr[$0]++;print $0,arr[$0]}' abc.txt
a 1
b 1
c 1
aa 1
bb 1
cc 1
a 2
b 2
c 2
2、在awk中使⽤for循环遍历数组中的每个元素
【例4】在awk中创建weekdays数组,并添加两个元素[root@magedu ~]# awk 'BEGIN{weekdays["mon"]="Monday";weekdays["tue"]="Tuesay";for(i in weekdays) {print weekdays[i]}}'
Monday
Tuesay
【例5】统计netstat -tan命令结果中各个状态的数量 ⽣成TIME-WAIT连接:
#需要开启httpd服务
[root@magedu ~]# ab -c 10 -n 200 http://172.16.103.78/
统计各个tcp状态的个数:
[root@magedu ~]# ss -tan|awk '!/State/{state[$1]++}END{for(i in state){print i,state[i]}}'
ESTAB 1
TIME-WAIT 207
LISTEN 15
【例6】统计httpd的访问⽇志中每个ip访问的次数
[root@magedu ~]# awk '{ip[$1]++}END{for(i in ip){print i,ip[i]}}' /var/log/httpd/access_log
172.18.120.26 261
172.18.116.232 3
【例7】统计连接本机的ip地址出现的次数
[root@magedu ~]# ss -nt|awk -F '[ :]+' '!/State/{ip[$(NF-2)]++}END{for(i in ip){print i,ip[i]}}'
172.16.101.234 1
或统计访问次数前⼗的ip地址:
[root@magedu ~]# ss -nt|awk -F '[ :]+' '!/State/{ip[$(NF-2)]++}END{for(i in ip){print i,ip[i]}}' | sort -nr -k2 | head
【例8】查找连接本机的次数⼤于20的ip地址,加⼊到防⽕墙禁⽌连接
[root@magedu ~]# ss -nt | awk -F'[ :]+' '!/State/{ip[$(NF-2)]++}END{for(i in ip){print i,ip[i]}}' | while read line; do ip=`echo $line | awk '{if($2>20)print $1}'`;[ -z "$ip" ]|| iptables -A INPUT -s $ip -j REJECT; done
或⽤cut简单简单实现:
[root@magedu ~]# ss -nt | awk -F'[ :]' '!/State/{ip[$(NF-2)]++}END{for(i in ip){print i,ip[i]}}' |while read line; do num=`echo $line | cut -d" " -f2`; ip=`echo $line | cut -d" " -f1`;[ $num -gt 3 ] && iptables -A INPUT -s $ip -j REJECT; done
【例9】有⼀个score.txt的⽂件,其内容是学⽣姓名、性别和分数,要求男⽣和⼥⽣的平均分
[root@magedu ~]# cat socre.txt
name sex score
mage m 100
wang m 90
li f 99
zhap f 95
[root@magedu ~]# awk '!/name/{if($2=="m"){m++;msum+=$3};if($2=="f"){f++;fsum+=$3}}END{print "mavg="msum/m,"favg="fsum/f}' socre.txt
mavg=95 favg=97
或:
[root@magedu ~]# awk '!/name/{num[$2]++;sum[$2]+=$3}END{for(i in num){print i " avg="sum[i]/num[i]}}' socre.txt
m avg=95
f avg=97
实验⼋:awk的函数
⽬的
掌握awk的常用函数,当然awk还有很多内置函数,如需要学习更多内容还有参考相关手册。下面介绍几个常用函数 的使用:
数值处理:
rand():返回0和1之间的一个随机数,搭配srand()使用
字符串处理:
- length([s]):返回指定s字符串的长度
- sub(r,s[t]):对t字符串进行搜索r表示的模式匹配的内容,并将第一个匹配的内容替换为s
- gsub(r,s,[t]):对t字符串进行搜索r表示的模式匹配的内容,并全部替换为s所表示的内容
- split(s,array,[r]):以r为分隔符,切割字符串s,并将切割后的结果保存至array所表示的数组中,第一个索引值为1,第二个索引值为2,...
⾃定义函数:
格式:
function name (parameter1, parameter2, ...){
statemenets
return expression
}
前提
可用的centos6系统。
实验步骤
1、rand()函数:⽣成随机数
【例1】⽣成⼀个0到1之间的随机数[root@magedu ~]# awk 'BEGIN{print rand()}'
0.237788
[root@magedu ~]# awk 'BEGIN{print rand()}'
0.237788
[root@magedu ~]# awk 'BEGIN{print rand()}'
0.237788
[root@magedu ~]# awk 'BEGIN{srand(); print rand()}'
0.792207
[root@magedu ~]# awk 'BEGIN{srand(); print rand()}'
0.046763
[root@magedu ~]# awk 'BEGIN{srand(); print rand()}'
0.046763
或使⽤shell中⽣成随机数的⽅法:
[root@magedu ~]# echo $RANDOM
8149
[root@magedu ~]# echo $RANDOM
29261
[root@magedu ~]# echo $RANDOM
10121
【例2】使⽤awk的循环,⽣成10个0-1之间的随机数
[root@magedu ~]# awk 'BEGIN{srand();for(i=0;i<10;i++)print rand()}'
0.90757
0.89926
0.390811
0.546444
0.441346
0.366411
0.17337
0.301543
0.51216
0.883284
【例3】使⽤awk的循环,利⽤int函数⽣成10个整数的随机数
[root@magedu ~]# awk 'BEGIN{srand();for(i=0;i<10;i++)print int(rand()*100)}'
1
68
10
71
94
19
77
23
18
83
2、length()函数:统计字符长度
【例4】计算“这是abc”的字符长度[root@magedu ~]# awk 'BEGIN{print length("这是abc")}'
5
3、sub()函数:替换第⼀次匹配的字符
【例5】把第⼀个冒号替换成连字符(-)[root@magedu ~]# echo "2018:08:17 15:47:50" |awk 'sub(/:/,"-",$1)'
2018-08:17 15:47:50
4、gsub()函数:全部替换
【例6】把所有冒号替换成连字符(-)[root@magedu ~]# echo "2018:08:17 15:47:50" |awk 'gsub(/:/,"-",$0)'
2018-08-17 15-47-50
5、split()函数:指定分隔符,分隔字符串
【例7】以冒号为分隔符,分别显⽰每个字段[root@magedu ~]# echo "2018:08:17 15:47:50" |awk '{split($0,array,":");print array[1]}'
2018
[root@magedu ~]# echo "2018:08:17 15:47:50" |awk '{split($0,array,":");print array[2]}'
08
[root@magedu ~]# echo "2018:08:17 15:47:50" |awk '{split($0,array,":");print array[3]}'
17 15
[root@magedu ~]# echo "2018:08:17 15:47:50" |awk '{split($0,array,":");print array[4]}'
47
[root@magedu ~]# echo "2018:08:17 15:47:50" |awk '{split($0,array,":");print array[5]}'
50
【例8】统计连接本机为建⽴状态的ip地址的数量
[root@magedu ~]# netstat -tn|awk '/^tcp\>/{split($5,ip,":");count[ip[1]]++}END{for(i in count){print i,count[i]}}'
172.16.101.234 1
6、⾃定义函数
【例9】获得两参数的最⼤值,⾃定义函数,在函数内部参数固定[root@magedu ~]# cat awk.fn
function max(v1,v2){
v1>v2?var=v1:var=v2
return var
}
BEGIN{a=3;b=2;print max(a,b)}
[root@magedu ~]# awk -f awk.fn
3
【例10】获得两参数的最⼤值,根据上例,把参数改为可变动的
[root@magedu ~]# cat awk.fn
function max(v1,v2){
v1>v2?var=v1:var=v2
return var
}
BEGIN{print max(a,b)}
[root@magedu ~]# awk -v a=10 -v b=30 -f awk.fn
30
实验九:awk调⽤系统命令和其他功能
⽬的
掌握awk调用linux的系统命令。
system命令;
空格是awk中的字符串连接符,如果system中需要使用awk中的变量可以使用空格分隔,或者说除了awk的变量外其 他一律用""引用起来。
awk的其他功能:
将awk程序写成脚本,直接调用或执行
向awk脚本传递参数
格式:awkfile var1=value1 var2=value2 ... Inputfile
注意:在BEGIN过程中不可使⽤,直到⾸⾏输⼊完成以后,变量才可⽤;可通过-v参数,让awk在执⾏BEGIN之前得到变
量的值;命令⾏中每⼀个指定的变量都需要⼀个-v参数。
前提
可用的centos6系统。
实验步骤
1、使⽤system()函数调⽤linux命令
【例1】在awk中调⽤linux系统的hostname命令[root@magedu ~]# hostname
magedu
[root@magedu ~]# awk 'BEGIN{system("hostname")}'
magedu
【例2】在awk中使⽤linux中echo命令显⽰awk中的变量
[root@magedu ~]# awk 'BEGIN{score=100;system("echo you score is "score)}'
you score is 100
【例3】在awk中使⽤iptables命令拒绝来源地址为1.1.1.1的访问
[root@magedu ~]# awk 'BEGIN{ip="1.1.1.1";system("iptables -A INPUT -s " ip " -j REJECT")}'
2、awk脚本
【例4】编写awk脚本,显⽰/etc/passwd中,uid⼤于500的⽤户和uid[root@magedu ~]# cat f1.awk
#!/bin/awk -f
{if($3>=500)print $1,$3}
[root@magedu ~]# chmod +x f1.awk
[root@magedu ~]# ./f1.awk -F: /etc/passwd
nfsnobody 65534
llj 500
li 501
zhang 502
python 503
3、给awk脚本传递参数
【例5】显⽰/etc/passwd⽂件中,uid在10-20之间的⽤户名和uid[root@magedu ~]# cat f2.awk
#!/bin/awk -f
{if($3>=min && $3<=max)print $1,$3}
[root@magedu ~]# chmod +x f2.awk
[root@magedu ~]# ./f2.awk -F: min=10 max=20 /etc/passwd
uucp 10
operator 11
games 12
gopher 13
ftp 14
或使⽤-v参数指定:
[root@magedu ~]# ./f2.awk -F: -v min=10 -v max=20 /etc/passwd