awk ‘{print “内容” > “文件名”}’ 文件名 #使用AWK打印内容追加到文件里面
awk ‘{ip[$1]++} END{for(i in ip){print ip[i],i}}’ /var/log/httpd/access_log | sort -n
统计访问http服务次数的IP地址公式必背
编写安全检测脚本
4.1 问题
本案例要求编写脚本,防止远程ssh暴力破解密码,具体监控项目要求如下:
检测ssh登录日志,如果远程登陆账号名错误3次,则屏蔽远程主机的IP
检测ssh登录日志,如果远程登陆密码错误3次,则屏蔽远程主机的IP
4.2 步骤
实现此案例需要按照如下步骤进行。
步骤一:准备工作
1)过滤帐户名失败的命令(登陆日志文件为/var/log/secure)
[root@svr5 ~]# awk ‘/Invalid user/{print $10}’ /var/log/secure
2)过滤密码失败的命令
[root@svr5 ~]# awk ‘/Failed password/{print $11}’ /var/log/secure
步骤二:编写参考脚本
1)脚本内容如下:
[root@svr5 ~]# vim test.sh
#!/bin/bash
awk ‘/Failed password/{print $11}’ /var/log/secure | awk ‘{ip[$1]++}END{for(i in ip){print ip[i],i}}’ | awk ‘$1>3{print $2}’
awk ‘/Invalid user/{print $10}’ /var/log/secure | awk ‘{ip[$1]++}END{for(i in ip){print ip[i],i}}’ | awk ‘$1>3{print $2}’
awk
相关命令:sed
awk是linux下的一个命令,他对其他命令的输出,对文件的处理都十分强大,其实他更像一门编程语言,他可以自定义变量,有条件语句,有循环,有数组,有正则,有函数等。他读取输出,或者文件的方式是一行,一行的读,根据你给出的条件进行查找,并在找出来的行中进行操作,感觉他的设计思想,真的很简单,但是结合实际情况,具体操作起来就没有那么简单了。他有三种形势,awk,gawk,nawk,平时所说的awk其实就是gawk。
选项
-F 紧跟分隔符,表示读入的字段以输入的分隔符分割
-v 进入变量模式 可以进行变量的赋值及调用(调用不需要加$符)
1,变量
变 量 描述
$n 当前记录的第n个字段,字段间由 FS分隔。
$0 完整的输入记录。
ARGC 命 令行参数的数目。
ARGIND 命令行中当前文件的位置(从0开始算)。
ARGV 包 含命令行参数的数组。
CONVFMT 数字转换格式(默认值为%.6g)
ENVIRON 环 境变量关联数组。
ERRNO 最后一个系统错误的描述。
FIELDWIDTHS 字 段宽度列表(用空格键分隔)。
FILENAME 当前文件名。
FNR 同 NR,但相对于当前文件。
FS 字段分隔符(默认是任何空格)。
IGNORECASE 如 果为真,则进行忽略大小写的匹配。
NF 当前记录中的字段数。
NR 当 前记录数。
OFMT 数字的输出格式(默认值是%.6g)。
OFS 输 出字段分隔符(默认值是一个空格)。
ORS 输出记录分隔符(默认值是一个换行符)。
RLENGTH 由 match函数所匹配的字符串的长度。
RS 记录分隔符(默认是一个换行符)。
RSTART 由 match函数所匹配的字符串的第一个位置。
SUBSEP 数组下标分隔符(默认值是\034)。
2,运算符
运算符 描述
= += -= *= /= %= ^= **= 赋值
?: C条件表达式
|| 逻 辑或
&& 逻辑与
~ ~! 匹 配正则表达式和不匹配正则表达式
< <= > >= != == 关 系运算符
空格 连接
-
- 加,减
- / & 乘,除与求余
-
- ! 一元加,减和逻辑非
^ *** 求幂
++ – 增加或减少,作为前缀或后缀
$ 字 段引用
in 数组成员
- ! 一元加,减和逻辑非
3,awk的正则
匹配符 描述
\Y 匹配一个单词开头或者末尾的空字符串
\B 匹配单词内的空字符串
< 匹配一个单词的开头的空字符串,锚定开始
> 匹配一个单词的末尾的空字符串,锚定末尾
\W 匹配一个非字母数字组成的单词
\w 匹配一个字母数字组成的单词
’ 匹配字符串末尾的一个空字符串
\‘ 匹配字符串开头的一个空字符串
4,字符串函数
函数名 描述
sub 匹配记录中最大、最靠左边的子字符串的正则表达式,并用替换字符串替换这些字符串。如果没有指定目标字符串就默认使用整个记录。替换只发生在第一次匹配的 时候
gsub 整个文档中进行匹配
index 返回子字符串第一次被匹配的位置,偏移量从位置1开始
substr 返回从位置1开始的子字符串,如果指定长度超过实际长度,就返回整个字符串
split 可按给定的分隔符把字符串分割为一个数组。如果分隔符没提供,则按当前FS值进行分割
length 返回记录的字符数
match 返回在字符串中正则表达式位置的索引,如果找不到指定的正则表达式则返回0。match函数会设置内建变量RSTART为字符串中子字符串的开始位 置,RLENGTH为到子字符串末尾的字符个数。substr可利于这些变量来截取字符串
toupper和tolower 可用于字符串大小间的转换,该功能只在gawk中有效
5,数学函数
函数名 返回值
atan2(x,y) y,x 范围内的余切
cos(x) 余弦函数
exp(x) 求 幂
int(x) 取整
log(x) 自然对 数
rand() 随机数
sin(x) 正弦
sqrt(x) 平 方根
srand(x) x是rand()函数的种子
int(x) 取 整,过程没有舍入
rand() 产生一个大于等于0而小于1的随机数
6,format的使用
要点:
1、其与print命令的最大不同是,printf需要指定format;
2、format用于指定后面的每个item的输出格式;
3、printf语句不会自动打印换行符;\n
format格式的指示符都以%开头,后跟一个字符;如下:
%c: 显示字符的ASCII码;
%d, %i:十进制整数;
%e, %E:科学计数法显示数值;
%f: 显示浮点数;
%g, %G: 以科学计数法的格式或浮点数的格式显示数值;
%s: 显示字符串;
%u: 无符号整数;
%%: 显示%自身;
修饰符:
N: 显示宽度;
-: 左对齐;
+:显示数值符号;
例1
测试文件test
root❌0:0:root:/root:/bin/bash
bin❌1:1:bin:/bin:/bin/false
daemon❌2:2:daemon:/sbin:/bin/false
mail❌8:12:mail:/var/spool/mail:/bin/false
ftp❌14:11:ftp:/home/ftp:/bin/false
&nobody:$:99:99:nobody:/:/bin/false
zhangy❌1000?,:/home/zhangy:/bin/bash
http❌33:33::/srv/http:/bin/false
dbus❌81:81:System message bus:/:/bin/false
hal❌82:82:HAL daemon:/:/bin/false
mysql❌89:89::/var/lib/mysql:/bin/false
aaa❌1001:1001::/home/aaa:/bin/bash
ba❌1002:1002::/home/zhangy:/bin/bash
test❌1003:1003::/home/test:/bin/bash
@zhangying:*:1004:1004::/home/test:/bin/bash
policykit❌102:1005:Po
例a
cat test | awk -F: ‘{
if ($1 == “root”){
print $1;
}else if($1 == “bin”){
print $2;
}else{
print $3;
}
}’
例b
awk ‘{
for(i=0;i<NF;i++){
if ($i ~/^root/){
print KaTeX parse error: Expected 'EOF', got '\ ' at position 3: i;\̲ ̲ }else if(i ~/zhangy/){
print KaTeX parse error: Expected 'EOF', got '\ ' at position 12: i;continue;\̲ ̲ }else if(i ~/mysql/){
print KaTeX parse error: Expected 'EOF', got '\ ' at position 8: i;next;\̲ ̲ }else if(i ~/^test/){
print $i;break;
}
}
}’ test
例c
tail test | awk ‘BEGIN{while(getline d){ split(d,test);for(i in test){
print test[i]
}}}’
例d
ls -al /home/zhangy/mytest | awk ‘BEGIN{while(getline d){ split(d,test);
print test[9] ;}
}’
例e
echo “32:34” |awk -F: ‘{print "max = ",max($1,$2)}
function max(one,two){
if(one > two){
return one;
}else{
return two;
}
}’
例f
awk -F: ‘{mat=match(
1
,
/
[
a
−
z
A
−
Z
]
+
1,/^[a-zA-Z]+
1,/[a−zA−Z]+/);print mat,RSTART,RLENGTH}’ test
例g
cat test |awk -F: ’
NF != 7{
printf(“line %d,does not have 7 fields:%s\n”,NR,$0)}
$1 !~ /1/{printf(“line %d,non alpha and numeric user id:%s: %s\n”,NR,$1,$0)}
$2 == “*” {printf(“lind %d,no password:%s\n”,NR,$0)}’
例2
测试文件
[root@Blackghost test2]# cat aaa //测试文件aaa
1111:23434:zhang
hoadsf:asdf:ccc
[root@Blackghost test2]# cat ccc //测试文件ccc
1111:23434:zhang
hoadsf:asdf:ccc
tank:zhang:x20342
ying:zhasdf:72342
hosa:asdfa:2345sdf
例a
[root@Blackghost test2]# awk ‘{print NR;print FNR;print $0;}’ aaa
1 //NR
1 //FNR
1111:23434:zhang
2
2
hoadsf:asdf:ccc
例b
[root@Blackghost test2]# awk ‘{print NR;print FNR;print $0;}’ aaa ccc
1
1
1111:23434:zhang
2 //NR
2 //FNR
hoadsf:asdf:ccc
3 //NR
1 //FNR 下面的数据是来自ccc,所以NFR重置为1
1111:23434:zhang
4
2
hoadsf:asdf:ccc
5
3
tank:zhang:x20342
6
4
ying:zhasdf:72342
7
5
hosa:asdfa:2345sdf
例3
只显示出现过一次的记录
cat aaa
59314
46791
59992
60311
60134
59992
60311
97343
cat aaa | awk ‘!a[$1]++’
59314
46791
59992
60311
60134
97343
例4
#输出/etc/passwd中关于root的第二个位置的内容
cat /etc/passwd |grep root |awk -F ‘:’ ‘{print $2}’
例5
处理前:
[root@practice ~]# ip addr show
1: lo: mtu 16436 qdisc noqueue
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
inet 10.99.133.33/32 scope global lo
2: eth2: mtu 1500 qdisc pfifo_fast qlen 1000
link/ether 0:1b:21:48:3e:b3 brd ff:ff:ff:ff:ff:ff
inet 172.20.33.44/23 brd 172.20.33.255 scope global eth2
3: eth3: mtu 1500 qdisc pfifo_fast qlen 1000
link/ether 00:1b:31:39:3e:2c brd ff:ff:ff:ff:ff:ff
4: eth0: mtu 1500 qdisc pfifo_fast qlen 1000
link/ether 00:25:29:09:8e:f2 brd ff:ff:ff:ff:ff:ff
inet 228.215.154.140/26 brd 228.215.154.191 scope global eth0
5: eth1: mtu 1500 qdisc pfifo_fast qlen 1000
link/ether 00:25:09:09:8e:f3 brd ff:ff:ff:ff:ff:ff
inet 228.215.154.150/26 brd228.215.154.191 scope global eth1
处理后
[root@practice ~]# ip addr show | awk ‘BEGIN{FS="[/ ]+";OFS=" – “}$2"eth"{$3~“NO-CARRIER”?a=0:a=1}$NF"eth”&&a{print $NF,$3}’
eth0 – 228.215.154.140
eth1 – 228.215.154.150
获取本机上网络接口上可用的公网IP地址
BEGIN{FS="[/ ]+";OFS=" – “} 是指把一个或多个空格或者/作为读取文本时的字段分隔符,把” – "作为执行完后的输出字段分隔符
$2"eth"{$3"NO-CARRIER"?a=0:a=1}找到第二个字段匹配到"eth"的行并判断第三个字段是否匹配到"NO-CARRIER",匹配到则a=0,否则a=1
$NF~“eth”&&a将最后一个字段和a相与,结果为真则打印最后一个字段和第三个字段,否则不处理
例6
awk取出last命令结果中非空行中的每
[root@practice ~]# last |awk ‘$0!=""&&$2!“boot”&&$3"[[:digit:]]"{ips[$3]++}END{for(i in ips)printf “%18-s%10-d\n”,i,ips[i]}’
172.20.33.1 1
172.20.33.95 7
192.168.2.100 6
192.168.2.101 3
172.20.33.26 1
192.168.2.102 8
172.20.32.123 7
192.168.140.1 2
172.20.33.93 1
&&表示 且,与
$0!=""表示排除结果中的空行
$2!~"boot"表示排除重启的记录
$3~"[[:digit:]]表示第三个字段匹配数字而不是字符
{ips[$3]++}表示把第三个字段即IP地址作为下标,组成一个数组ips,IP地址每出现一次,其出现次数累加一
END{for(i in ips)printf “%18-s%10-d\n”,i,ips[i]}
表示从数组中获取每个IP地址,及其出现的次数,并定义对齐方式和变量类型打印出来
例7
#将passwd中的第三列放到test中
[root@localhost ~]# awk -F: ‘{if(NR>=10 && NR<=20) print $3 }’ /etc/passwd > test
You have mail in /var/spool/mail/root
[root@localhost ~]# cat test
10
11
12
13
14
99
81
113
69
32
499
例8
[root@xuegod68 mnt]# head -5 2.txt
10.0.0.3 --[21/Mar/2015-07:50:17+0800]GET/HTTP/1.1200 19 -
10.0.0.3 --[21/Mar/2015-07:50:17+0800]GET/HTTP/1.1200 19 -
10.0.0.5 --[21/Mar/2015-07:50:17+0800]GET/HTTP/1.1200 19 -
10.0.0.3 --[21/Mar/2015-07:50:17+0800]GET/HTTP/1.1200 19 -
10.0.0.6 --[21/Mar/2015-07:50:17+0800]GET/HTTP/1.1200 19 -
[root@xuegod68 mnt]# awk ‘{array[$1]++} END {for(key in array) printkey,array[key]}’ 2.txt
10.0.0.3 35
10.0.0.4 5
10.0.0.5 10
10.0.0.6 10
例9
#将UID大于等于500的用户及UID打印出来
[root@localhost ~]# awk -F: ‘$3>=500 {print $1,$3}’ /etc/passwd
nfsnobody 65534
admin 502
test 503
步骤一:awk文本过滤的基本用法
1)基本操作方法
格式:awk [选项] ‘[条件]{指令}’ 文件
其中,print 是最常用的编辑指令;若有多条编辑指令,可用分号分隔。
Awk过滤数据时支持仅打印某一列,如第2列、第5列等。
处理文本时,若未指定分隔符,则默认将空格、制表符等作为分隔符。
直接过滤文件内容:
[root@svr5 ~]# awk ‘{print $1,$3}’ test.txt //打印文档第1列和第3列
结合管道过滤命令输出:
[root@svr5 ~]# df -h | awk ‘{print $4}’ //打印磁盘的剩余空间
选项 -F 可指定分隔符
输出passwd文件中以分号分隔的第1、7个字段,显示的不同字段之间以逗号隔开,操作如下:
[root@svr5 ~]# awk -F: ‘{print $1,$7}’ /etc/pass
awk还识别多种单个的字符,比如以“:”或“/”分隔,输出第1、10个字段:
[root@svr5 ~]# awk -F [?] ‘{print $1,$10}’ /etc/passwd
awk常用内置变量:
$1 文本的第1列
$2 文件的第2列
$3 文件的第3列,依此类推
NR 文件当前行的行号
NF 文件当前行的列数(有几列)
输出每次处理的行号,以及当前行以“:”分隔的字段个数:
[root@svr5 ~]# awk -F: ‘{print NR,NF}’ passwd.txt
awk的print指令不仅可以打印变量,还可以打印常量
[root@svr5 ~]# awk -F: ‘{print $1,“的解释器:”,$7}’ /etc/passwd
步骤二:利用awk提取本机的网络流量、根分区剩余容量、获取远程失败的IP地址
1)提取IP地址
分步实现的思路及操作参考如下——
通过ifconfig eth0查看网卡信息,其中包括网卡流量:
[root@svr5 ~]# ifconfig eth0
RX为接收的数据量,TX为发送的数据量。packets以数据包的数量为单位,bytes以字节为单位:
[root@svr5 ~]# ifconfig eth0 | awk ‘/RX p/{print $5}’ //过滤接收数据的流量
319663094
[root@svr5 ~]# ifconfig eth0 | awk ‘/TX p/{print $5}’ //过滤发送数据的流量
40791683
提取根分区剩余容量
分步实现的思路及操作参考如下——
通过df命令查看根分区的使用情况,其中包括剩余容量:
[root@svr5 ~]# df -h /
输出上述结果中最后一行的第4列:
[root@svr5 ~]# df -h / | tail -1 | awk ‘{print $6}’
11G
或者直接在awk中使用正则:
[root@svr5 ~]# df -h | awk ‘//$/{print $4}’
11G
根据/var/log/secure日志文件,过滤远程连接密码失败的IP地址
[root@svr5 ~]# awk ‘/Failed/{print $11}’ /var/log/secure
步骤三:格式化输出/etc/passwd文件
1)awk处理的时机
awk会逐行处理文本,支持在处理第一行之前做一些准备工作,以及在处理完最后一行之后做一些总结性质的工作。在命令格式上分别体现如下:
awk [选项] ’ BEGIN{指令} {指令} END{指令}’ 文件
BEGIN{ } 行前处理,读取文件内容前执行,指令执行1次
{ } 逐行处理,读取文件过程中执行,指令执行n次
END{ } 行后处理,读取文件结束后执行,指令执行1次
只做预处理的时候,可以没有操作文件,比如:
[root@svr5 ~]# awk ‘BEGIN{A=24;print A*2}’
[root@svr5 ~]# awk ‘BEGIN{print x+1}’
[root@svr5 ~]# awk ‘BEGIN{print 3.2+3.5}’
举个例子(统计系统中使用bash作为登录Shell的用户总个数):
a.预处理时赋值变量x=0
b.然后逐行读入/etc/passwd文件,如果发现登录Shell是/bin/bash则x加1
c.全部处理完毕后,输出x的值即可。相关操作及结果如下:
[root@svr5 ~]# awk ‘BEGIN{x=0}/bash$/{x++} END{print x}’ /etc/passwd
使用正则设置条件,输出其中以bash结尾的完整记录:
[root@svr5 ~]# awk -F: ‘/bash$/{print}’ /etc/passwd
输出包含root的行数据:
[root@svr5 ~]# awk -F: ‘/root/’ /etc/passwd
输出root或adm账户的用户名和UID信息:
[root@svr5 ~]# awk -F: ‘/^(root|adm)/{print $1,$3}’ /etc/passwd
输出账户名称包含root的基本信息(第1列包含root):
[root@svr5 ~]# awk -F: ‘$1~/root/’ /etc/passwd
输出其中登录Shell不以nologin结尾(对第7个字段做!~反向匹配)的用户名、登录Shell信息:
[root@svr5 ~]# awk -F: ‘
7
!
/
n
o
l
o
g
i
n
7!~/nologin
7! /nologin/{print $1,$7}’ /etc/passwd
使用数值/字符串比较设置条件
比较符号:==(等于) !=(不等于) >(大于)
=(大于等于) <(小于) <=(小于等于)
输出第3行(行号NR等于3)的用户记录:
[root@svr5 ~]# awk -F: ‘NR==3{print}’ /etc/passwd
输出账户UID大于等于1000的账户名称和UID信息:
[root@svr5 ~]# awk -F: ‘$3>=1000{print $1,$3}’ /etc/passwd
输出账户UID小于10的账户名称和UID信息:
[root@svr5 ~]# awk -F: ‘$3<10{print $1,$3}’ /etc/passwd
输出用户名为“root”的行:
[root@svr5 ~]# awk -F: ‘$1==“root”’ /etc/passwd
逻辑测试条件
输出账户UID大于10并且小于20的账户信息:
[root@svr5 ~]# awk -F: ‘$3>10 && $3<20’ /etc/passwd
输出账户UID大于1000或者账户UID小于10的账户信息:
[root@svr5 ~]# awk -F: ‘$3>1000 || $3<10’ /etc/passwd
数学运算
[root@svr5 ~]# awk ‘BEGIN{x++;print x}’
1
[root@svr5 ~]# awk ‘BEGIN{x=8;print x+=2}’
10
[root@svr5 ~]# awk ‘BEGIN{x=8;x–;print x}’
7
[root@svr5 ~]# awk ‘BEGIN{print 2+3}’
5
[root@svr5 ~]# awk ‘BEGIN{print 23}’
6
[root@svr5 ~]# awk 'BEGIN{print 23}’
6
[root@svr5 ~]# awk ‘BEGIN{ print 23%8}’
7
[root@svr5 ~]# seq 200 | awk ‘$1%3==0{i++} END{print i}’ //统计3的倍数的数量
66
)列出UID间于1~1000的用户详细信息:
[root@svr5 ~]# awk -F: ‘$3>=1 && $3<=1000’ /etc/passwd
2)输出/etc/hosts映射文件内以127或者192开头的记录:
[root@svr5 ~]# awk -F: ‘/^(127|192)/’ /etc/hosts
列出100以内整数中7的倍数或是含7的数:
[root@svr5 ~]# seq 100 | awk ‘$1%7==0||$1~/7/{print}’
7
:根据实现思路编写脚本
复制原getupwd.sh脚本,生成getupwd-awk.sh:
[root@svr5 ~]# cat getupwd-awk.sh //确认原脚本内容
#/bin/bash
A=
(
a
w
k
–
F
:
′
/
b
a
s
h
(awk –F: '/bash
(awk–F:′/bash/{print $1}’ /etc/passwd) ## 提取符合条件的账号记录
for i in $A
do
pass1=grep $i /etc/passwd
##过滤单个账户信息
pass2=KaTeX parse error: Expected '}', got '#' at position 7: {pass1#̲*:} …{pass2%%?} ##对数据去尾
echo “$i --> $pass” >> /tmp/getupwd.log ## 保存结果
done
echo “用户分析完毕,请查阅文件 /tmp/getupwd.log” ## 完成后提示
:验证、测试脚本
[root@svr5 ~]# ./getupwd-awk.sh
用户分析完毕,请查阅文件 /tmp/getupwd.log
[root@svr5 ~]# head -5 /tmp/getupwd.lo
实现此案例需要按照如下步骤进行。
步骤一:awk过滤中的if分支结构
1)单分支
统计/etc/passwd文件中UID小于或等于1000的用户个数:
[root@svr5 ~]# awk -F: ‘{if($3<=1000){i++}}END{print i}’ /etc/passwd
39
统计/etc/passwd文件中UID大于1000的用户个数:
[root@svr5 ~]# awk -F: ‘{if($3>1000){i++}}END{print i}’ /etc/passwd
8
统计/etc/passwd文件中登录Shell是“/bin/bash”的用户个数:
[root@svr5 ~]# awk -F: ‘{if(
7
/
b
a
s
h
7~/bash
7 /bash/){i++}}END{print i}’ /etc/passwd
29
2)双分支
分别统计/etc/passwd文件中UID小于或等于1000、UID大于1000的用户个数:
[root@svr5 ~]# awk -F: ‘{if($3<=500){i++}else{j++}}END{print i,j}’ /etc/passwd
39 8
分别统计/etc/passwd文件中登录Shell是“/bin/bash”、 登录Shell不是“/bin/bash”的用户个数:
[root@svr5 ~]# awk -F: ‘{if(
7
/
b
a
s
h
7~/bash
7 /bash/){i++}else{j++}} END{print i,j}’ /etc/passwd
:awk数组
1)数组的语法格式
数组是一个可以存储多个值的变量,具体使用的格式如下:
定义数组的格式:数组名[下标]=元素值
调用数组的格式:数组名[下标]
遍历数组的用法:for(变量 in 数组名){print 数组名[变量]}。
[root@svr5 ~]# awk ‘BEGIN{a[0]=11;a[1]=88;print a[1],a[0]}’
88 11
[root@svr5 ~]# awk ‘BEGIN{a++;print a}’
1
[root@svr5 ~]# awk ‘BEGIN{a0++;print a0}’
1
[root@svr5 ~]# awk ‘BEGIN{a[0]++;print a[0]}’
1
[root@svr5 ~]# awk ‘BEGIN{a[0]=00;a[1]=11;a[2]=22; for(i in a){print i,a[i]}}’
,awk数组的下标除了可以使用数字,也可以使用字符串,字符串需要使用双引号:
[root@svr5 ~]# awk ‘BEGIN{a[“hehe”]=11;print a[“hehe”]}’
:awk扩展应用
5.1 问题
本案例要求使用awk工具完成下列两个任务:
分析Web日志的访问量排名,要求获得客户机的地址、访问次数,并且按照访问次数排名
5.2 方案
1)awk统计Web访问排名
在分析Web日志文件时,每条访问记录的第一列就是客户机的IP地址,其中会有很多重复的IP地址。因此只用awk提取出这一列是不够的,还需要统计重复记录的数量并且进行排序。
通过awk提取信息时,利用IP地址作为数组下标,每遇到一个重复值就将此数组元素递增1,最终就获得了这个IP地址出现的次数。
针对文本排序输出可以采用sort命令,相关的常见选项为-r、-n、-k。其中-n表示按数字顺序升序排列,而-r表示反序,-k可以指定按第几个字段来排序。
5.3 步骤
实现此案例需要按照如下步骤进行。
步骤一:统计Web访问量排名
分步测试、验证效果如下所述。
1)提取IP地址及访问量
[root@svr5 ~]# awk '{ip[$1]++} \
END{for(i in ip) {print i,ip[i]}}’ /var/log/httpd/access_log
2)对第1)步的结果根据访问量排名
[root@svr5 ~]# awk ‘{ip[$1]++} END{for(i in ip) {print i,ip[i]}}’ /var/log/httpd/access_log | sort -nr -k 2
A-Za-z0-9 ↩︎