awk工具概述
- awk编程语言/数据处理引擎
- 创造者: Aho Weinberger Kerninghan
- 基于模式匹配检查输入文本,获取指定的数据
- 通常用在shell脚本中,获取指定的数据
- 单独使用时,可对文本数据做统计
- 优点就是精确查找,唯一缺点就是不能修改文件
awk命令格式
- 格式1 : 前置命令 | awk [选项] '{(条件)指令}'
- 格式2 : awk [选项] '{(条件)指令}' 被处理的文件
- 条件类似sed定址符,但是功能更强大
常用命令选项
- -F : 指定分隔符,可省略(默认空格或Tab位)
- -v var=value : 自定义变量
常用指令
- print : 输出
awk内置变量
- 有特殊含义,可直接使用
变量 | 含义 |
FS | 保存或设置字段分隔符,例如FS=":" , 与 -F 功能一样 |
$n | 指定分隔的第n个字段,如$1.$3分别表示第1列,第3列 |
$0 | 当前读入的整行文本内容(文本当前行的全部内容) |
NF | 记录当前处理的字段个数(列数) |
NR | 记录当前已读入行的数量(行数) |
- "" : 常量,一般写提示语
- \t : Tab制表键
- , : 可以实现$n之间的空格效果
[root@proxy mnt]# cat nns ##以nns作为素材
Hello the worlD
welcome to bEijing
[root@proxy mnt]# awk '{print $1,$2}' nns ##列出全文第1列和第2列
Hello the
welcome to
[root@proxy mnt]# awk '{print $3,$1}' nns ##列出全文第3列和第1列
worlD Hello
bEijing welcome
[root@proxy mnt]# awk '{print $0}' nns ##列出全文
Hello the worlD
welcome to bEijing
[root@proxy mnt]# awk '{print}' nns ##效果同上
Hello the worlD
welcome to bEijing
[root@proxy mnt]# awk '{print $3,$0}' nns ##列出第3列和全文
worlD Hello the worlD
bEijing welcome to bEijing
[root@proxy mnt]# cat test ##以test作为素材
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
[root@proxy mnt]# awk '{print $1}' test ##默认空格为分隔符,所以输出全文
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
[root@proxy mnt]# awk -F: '{print $1}' test ##定义:为分隔符,所以输出全文第一列
root
bin
daemon
adm
lp
[root@proxy mnt]# awk -F: '{print $5}' test ##定义:为分隔符,所以输出全文第5列
root
bin
daemon
adm
lp
[root@proxy mnt]# awk -F: '{print $6}' test ##定义:为分隔符,所以输出全文第6列
root
/root
/bin
/sbin
/var/adm
/var/spool/lpd
[root@proxy mnt]# awk -F: '{print $7}' test ##定义:为分隔符,所以输出全文第6列
/bin/bash
/sbin/nologin
/sbin/nologin
/sbin/nologin
/sbin/nologin
[root@proxy mnt]# awk -F: '/root/{print $1}' test
root ##定义:为分隔符,列出有root的行的第1列
[root@proxy mnt]# awk -F: '/^bin/{print $1}' test
bin ##定义:为分隔符,列出以bin开头的行的第1列
[root@proxy mnt]# awk -F: '{print $1"的家目录是"$7}' test ##配合常量显示
root的家目录是/root
bin的家目录是/bin
daemon的家目录是/sbin
adm的家目录是/var/adm
lp的家目录是/var/spool/lpd
[root@proxy mnt]# awk -F: '{print $1"的UID是"$3}' test ##配合常量显示
root的UID是0
bin的UID是1
daemon的UID是2
adm的UID是3
lp的UID是4
[root@proxy mnt]# awk -F[:/] '{print $10}' test ##定义:/为分隔符,所以一行有10列
bash
nologin
nologin
sbin
[root@proxy mnt]# awk -F: '{print NF}' test ##定义:为分隔符,列出所有行的所有列数
7
7
7
7
7
[root@proxy mnt]# awk -F: '{print NR}' test ##定义:为分隔符,列出所有行数
1
2
3
4
5
[root@proxy mnt]# awk -F: '{print NR,NF}' test ##定义:为分隔符,列出所有行数和列数
1 7
2 7
3 7
4 7
5 7
用awk截取接收流量
[root@proxy mnt]# ifconfig eth0
eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 192.168.4.207 netmask 255.255.255.0 broadcast 192.168.4.255
ether 52:54:00:67:2e:b5 txqueuelen 1000 (Ethernet)
RX packets 9009 bytes 654078 (638.7 KiB)
RX errors 0 dropped 3893 overruns 0 frame 0
TX packets 3303 bytes 399300 (389.9 KiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
- RX : 代表接收流量
- TX : 代表发送流量
[root@proxy mnt]# ifconfig eth0 | awk '/RX pa/{print $4,$5}' ##列出接收流量
bytes 676314
[root@proxy mnt]# ifconfig eth0 | awk '/RX pa/{print $4,$5}' ##列出发送流量
bytes 676894
[root@proxy mnt]# ifconfig eth0 | awk '/RX p/{print "eth0的接收流量是"$5" 字节"}'
eth0的接收流量是719538字节 ##用常量表示
[root@proxy mnt]# ifconfig eth0 | awk '/TX p/{print "eth0的发送流量是"$5" 字节"}'
eth0的发送流量是439372字节 ##用常量表示
使用awk提取根分区剩余容量(提取硬盘空间信息)
[root@proxy mnt]# df -h
文件系统 容量 已用 可用 已用% 挂载点
/dev/vda1 30G 1.9G 29G 7% /
devtmpfs 697M 0 697M 0% /dev
tmpfs 707M 0 707M 0% /dev/shm
tmpfs 707M 8.5M 699M 2% /run
tmpfs 707M 0 707M 0% /sys/fs/cgroup
tmpfs 142M 0 142M 0% /run/user/0
- 找以/结尾的剩余容量
[root@proxy mnt]# df -h | awk '/\/$/{print "根分区剩余容量是"$3}'
根分区剩余容量是1.9G
查找访问本机密码输入失败的IP信息
- /var/log/secure ##这个文件是存放用户远程登录信息的文件
[root@proxy mnt]# tail /var/log/secure
Jan 8 12:55:58 proxy sshd[13949]: pam_unix(sshd:auth): authentication failure; logname= uid=0 euid=0 tty=ssh ruser= rhost=192.168.4.6 user=root
Jan 8 12:55:58 proxy sshd[13949]: pam_succeed_if(sshd:auth): requirement "uid >= 1000" not met by user "root"
Jan 8 12:56:00 proxy sshd[13949]: Failed password for root from 192.168.4.6 port 41394 ssh2
Jan 8 12:56:01 proxy sshd[13949]: pam_succeed_if(sshd:auth): requirement "uid >= 1000" not met by user "root"
Jan 8 12:56:02 proxy sshd[13949]: Failed password for root from 192.168.4.6 port 41394 ssh2
Jan 8 12:56:03 proxy sshd[13949]: pam_succeed_if(sshd:auth): requirement "uid >= 1000" not met by user "root"
Jan 8 12:56:06 proxy sshd[13949]: Failed password for root from 192.168.4.6 port 41394 ssh2
Jan 8 12:56:06 proxy sshd[13949]: error: maximum authentication attempts exceeded for root from 192.168.4.6 port 41394 ssh2 [preauth]
Jan 8 12:56:06 proxy sshd[13949]: Disconnecting: Too many authentication failures [preauth]
Jan 8 12:56:06 proxy sshd[13949]: PAM 2 more authentication failures; logname= uid=0 euid=0 tty=ssh ruser= rhost=192.168.4.6 user=root
[root@proxy mnt]# awk '/Failed/{print $11}' /var/log/secure
student
student
student
student
student
student
student
student
student
192.168.4.6
192.168.4.6
192.168.4.6
192.168.4.6
awk处理时机
- BEGIN{} 在所有行前处理 (指令执行1次)
- 在读入第一行文本之前执行
- 一般用来初始化操作
- {} 逐行处理 (指令执行n次)
- 逐行读入文本执行相应的处理
- 是最常见的编辑指令块
- END{} 在所有行后处理 (指令执行1次)
- 处理完最后一行文本之后执行
- 一般用来输出处理结果
- 格式 : awk 'BEGIN{指令1次}{逐行任务n次}END{指令1次}'
[root@proxy mnt]# awk 'BEGIN{print "abc"}' ##列出常量abc一次
abc
[root@proxy mnt]# awk 'BEGIN{print NR}{print "abc"}' test
0
abc
abc
abc
abc
abc ##执行一次BEGIN后,再逐行处理
[root@proxy mnt]# awk '{print "abc"}' test ##全文逐行处理,输出abc
abc
abc
abc
abc
abc
[root@proxy mnt]# awk 'BEGIN{print NR}{print NR}END{print NR}' test
0
1
2
3
4
5
5 ##添加了end任务,多输出最后一行的行号
[root@proxy mnt]# awk 'BEGIN{print NR}{print NR}' test
0
1
2
3
4
5
[root@proxy mnt]# awk 'BEGIN{A=24; print A*2}' ## 定义变量,做运算
48
[root@proxy mnt]# awk 'BEGIN{A=0}{A++}END{print A}' test
5 ##定义变量,做逐行运算,最后输出值
[root@proxy mnt]# awk 'BEGIN{print "abc"}{print "xyz"}END{print "789"}' test
abc
xyz
xyz
xyz
xyz
xyz
789 ##列出常量ABC 1次 逐行处理输出xyz 最后列出789
[root@proxy mnt]# awk -F: 'BEGIN{print "abc"}{print $1}END{print NR}' test
abc
root
bin
daemon
adm
lp
5 ##列出常量ABC 1次 逐行处理输出第1列 最后列出逐行处理的行数
[root@proxy mnt]# awk 'BEGIN{print NR}' test ##输出一次行号,第一行之前的行号,结果为0
0
使用AWK格式化输出文档内容
[root@proxy mnt]# awk -F: 'BEGIN{print "USER\tUID\tHome"}' ##行前输出
USER UID Home
[root@proxy mnt]# awk -F: '{print $1"\t"$3"\t"$6}' test ##逐行处理
root 0 /root
bin 1 /bin
daemon 2 /sbin
adm 3 /var/adm
lp 4 /var/spool/lpd
[root@proxy mnt]# awk -F: 'END{print "总计"NR"行"}' test ##行后输出
总计5行
[root@proxy mnt]# awk -F: 'BEGIN{print "USER\tUID\tHome"}{print $1"\t"$3"\t"$6}END{print "总计"NR"行"}' test
USER UID Home
root 0 /root
bin 1 /bin
daemon 2 /sbin
adm 3 /var/adm
lp 4 /var/spool/lpd
总计5行 ##组合打印列表
条件的表达形式:
- 正则设置条件
符号 | 含义 |
/ / | 一般写在{}前,匹配正则表达式 |
~ | 包含 |
!~ | 不包含 |
[root@proxy mnt]# awk '/root/{print}' test ##如果print后不跟内置变量,可以省略
root:x:0:0:root:/root:/bin/bash
[root@proxy mnt]# awk '/root/' test ##效果同上
root:x:0:0:root:/root:/bin/bash
[root@proxy mnt]# awk '/root|bin/' test ##列出有root或者有bin的行
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
[root@proxy mnt]# awk '/^root|^bin/' test ##列出以root开头或者以bin开头的行
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
[root@proxy mnt]# awk -F: '$6~/root/' test ##列出第6列包含root的行
root:x:0:0:root:/root:/bin/bash
[root@proxy mnt]# awk -F: '$1~/root/' test ##列出第1列包含root的行
root:x:0:0:root:/root:/bin/bash
[root@proxy mnt]# awk -F: '$1!~/root/' test ##列出第1列不包含root的行
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
- 数值/字符串比较
比较符号 : | 含义 |
== | 等于 |
!= | 不等于 |
> | 大于 |
>= | 大于等于 |
< | 小于 |
<= | 小于等于 |
[root@proxy mnt]# awk 'NR==2' test ##列出第2行
bin:x:1:1:bin:/bin:/sbin/nologin
[root@proxy mnt]# awk -F: '$1=="root"' test ##列出第1列必须是root的行
root:x:0:0:root:/root:/bin/bash
[root@proxy mnt]# awk -F: '$1~/root/' test ##列出第1列包含root的行,范围广
root:x:0:0:root:/root:/bin/bash
[root@proxy mnt]# awk -F: '$1!="root"' test ##列出第1列不是root的行
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
[root@proxy mnt]# awk 'NR>2' test ##列出大于2的行
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
[root@proxy mnt]# awk 'NR<=2' test ####列出小于等于2的行
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
[root@proxy mnt]# awk -F: '$3<=10' /etc/passwd ##列出UID<=10的行
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
- 逻辑比较
- 条件 : && 并且 期望多个条件都成立
- 条件 : || 或者 只要有一个条件成立即满足要求
[root@proxy mnt]# awk -F: 'NR>=1&&NR<=3' test ##列出1-3行
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
[root@proxy mnt]# awk -F: '$3<=5||$3>=1000' /etc/passwd
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
nginx:x:1000:1000::/home/nginx:/sbin/nologin
lisi:x:1001:1001::/home/lisi:/bin/bash
haha:x:1002:1002::/home/haha:/bin/bash
zhang:x:1003:1003::/home/zhang:/bin/bash
kaka:x:1004:1004::/home/kaka:/bin/bash
tian:x:1005:1005::/home/tian:/bin/bash
titi:x:1008:1008::/home/titi:/bin/bash ##列出UID小于等于5或者大于等于1000
nfsnobody:x:65534:65534:Anonymous NFS User:/var/lib/nfs:/sbin/nologin
[root@proxy mnt]# awk -F: '$3<10||$3>1000' /etc/passwd ##列出UID小于5或者大于1000
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
lisi:x:1001:1001::/home/lisi:/bin/bash
haha:x:1002:1002::/home/haha:/bin/bash
zhang:x:1003:1003::/home/zhang:/bin/bash
kaka:x:1004:1004::/home/kaka:/bin/bash
tian:x:1005:1005::/home/tian:/bin/bash
titi:x:1008:1008::/home/titi:/bin/bash
nfsnobody:x:65534:65534:Anonymous NFS User:/var/lib/nfs:/sbin/nologin
[root@proxy mnt]# awk -F: '$3<10&&$3>1000' /etc/passwd ##逻辑错误
列出/etc/hosts/ 文件内以192开头或者以127开头的记录
[root@proxy mnt]# cat /etc/hosts
# ::1 localhost localhost.localdomain localhost6 localhost6.localdomain6
127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4
192.168.4.207 www.a.com
192.168.4.208 www.b.com
[root@proxy mnt]# awk -F. '$1==127||$1==192' /etc/hosts
127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4
192.168.4.207 www.a.com
192.168.4.208 www.b.com
- 运算符
运算符 | 作用 |
+ | 加法运算 |
- | 减法运算 |
* | 乘法运算 |
/ | 除法运算 |
% | 取余运算 |
++ | 自增1 |
-- | 自减1 |
-= | 减法运算 |
*= | 乘法运算 |
/= | 除法运算 |
%= | 取余运算 |
[root@proxy mnt]# awk 'BEGIN{print 1+1}' ##加法运算
2
[root@proxy mnt]# awk 'BEGIN{print 1-1}' ##减法运算
0
[root@proxy mnt]# awk 'BEGIN{print 1*1}' ##乘法运算
1
[root@proxy mnt]# awk 'BEGIN{print 2/2}' ##除法运算
1
[root@proxy mnt]# awk 'BEGIN{print 2%2}' ##取余运算
0
[root@proxy mnt]# awk 'BEGIN{a=10;print a}' ##定义变量,输出变量
10
[root@proxy mnt]# awk 'BEGIN{a=10;a++;print a}' ##定义变量,运算变量,输出变量
11
[root@proxy mnt]# awk 'BEGIN{a=10;a++;print a+=10}' ##定义变量,运算变量,输出变量
21
[root@proxy mnt]# awk 'BEGIN{a=10;print a%=7}' ##取余运算
3
列出100以内整数中7的倍数或是含7的数
思路:
- 1. seq 100 ##输出1-100的数字
- 2. seq 100 | awk '$1~/7/' ##输出1-100数字之内包含7的数字
- 3.seq 100 | awk '$1%7==0' ##输出1-100数字之内7的倍数
[root@proxy mnt]# seq 100 | awk '$1%7==0||$1~/7/'
7
14
17
21
27
28
35
37
42
47
49
56
57
63
67
70
71
72
73
74
75
76
77
78
79
84
87
91
97
98
awk综合脚本示例
- 编写脚本的任务要求如下:
- 找到使用bash作登录Shell的本地用户
- 列出这些用户的shadow密码记录,如图所示
[root@proxy mnt]# vim test08.sh
#!/bin/bash
#这是一个显示能登录shell环境的用户跟用户密码信息的测试脚本
user=`awk -F: '/bash$/{print $1}' /etc/passwd`
for i in $user
do
grep $i /etc/shadow | awk -F: '{print $1"--->"$2}'
done
[root@proxy mnt]# bash test08.sh ##效果如图所示
awk高级应用
awk流程控制
分支结构:
- 单分支
if(条件){编辑指令}
- 双分支
if(条件){编辑指令1}else{编辑指令2}
- 多分支
if(条件){编辑指令1}else if(条件){编辑指令2}...else{编辑指令N}
单分支练习
统计/etc/passwd文件中UID小于或等于1000的用户个数:
[root@proxy mnt]# awk -F: '{if($3<=1000){i++}}END{print i}' /etc/passwd
24
统计/etc/passwd文件中UID大于1000的用户个数:
[root@proxy mnt]# awk -F: '{if($3>1000){i++}}END{print i}' /etc/passwd
7
统计/etc/passwd文件中登录Shell是“/bin/bash”的用户个数:
[root@proxy ~]# awk -F: '{if($7~/bash$/){i++}}END{print i}' /etc/passwd
7
[root@proxy mnt]# cat test ##以test作为素材
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
[root@proxy mnt]# awk -F: '{if($3==0){print}}' test ##打印UID为0的行
root:x:0:0:root:/root:/bin/bash
双分支练习
分别统计/etc/passwd文件中UID小于或等于1000、UID大于1000的用户个数:
[root@proxy ~]# awk -F: '{if($3>=1000){x++}else{y++}}END{print x,y}' /etc/passwd
8 23
分别统计/etc/passwd文件中登录Shell是“/bin/bash”、 登录Shell不是“/bin/bash”的用户个数:
[root@proxy ~]# awk -F: '{if($7~/bash$/){i++}else{j++}} END{print i,j}' /etc/passwd
7 24
多分支练习
列出UID小于等于10或者大于1000的数量,并统计总数:
[root@proxy ~]# awk -F: 'BEGIN{x=0;y=0;z=0}{if($3<=10){x++}else if($3>1000){y++}else{z++}}END{print x,y,z}' /etc/passwd
9 7 15
加上常量显示:
[root@proxy ~]# awk -F: 'BEGIN{x=0;y=0;z=0}{if($3<=10){x++}else if($3>1000){y++}else{z++}}END{print "UID小于10的数量是"x,"UID大于10的数量是"y,"两者总数是"z}' /etc/passwd
UID小于10的数量是9 UID大于10的数量是7 两者总数是15
awk数组
数组的语法格式:
数组是一个可以存储多个值的变量,具体使用的格式如下:
- 定义数组的格式:数组名[下标]=元素值
- 下标可以是数字或者字母或者变量
- 调用数组的格式:数组名[下标]
- 遍历数组的用法:for(变量 in 数组名){print 数组名[变量]}。
- 定义数组后配合for循环可以方便的查看数组所有内容,次过程成为遍历数组
下标和值可以不用数字
定义数组a自增1,输出结果:
[root@svr5 ~]# awk 'BEGIN{a[0]++;print a[0]}'
1
定义数组a,for循环数组a,由于数组a只有三个下标所以循环3次并输出下标及对应下标的值:
[root@svr5 ~]# awk 'BEGIN{a[0]=0;a[1]=11;a[2]=22; for(i in a){print i,a[i]}}'
0 0
1 11
2 22
定义数组a,下标分别是1和2,然后输出该数组对应下标的值:
[root@proxy ~]# awk 'BEGIN{a[1]=100;a[2]=200;print a[1],a[2]}'
100 200
调用数组的顺序:
[root@proxy ~]# awk 'BEGIN{a[1]=100;a[2]=200;print a[2],a[1]}'
200 100
对定义好的数组做运算:
[root@proxy ~]# awk 'BEGIN{a[1]=100;a[1]++;print a[1]}'
101
定义数组a,for循环遍历数组下标:
[root@proxy ~]# awk 'BEGIN{a[1]=100;a[2]=200;for(i in a){print i}}'
1
2
定义数组a,for循环遍历数组a:
[root@proxy ~]# awk 'BEGIN{a[1]=100;a[2]=200;for(i in a){print i,a[i]}}'
1 100
2 200
定义数组的下标为字母a,需要用""引起来
[root@proxy mnt]# awk 'BEGIN{a["a"]="abc";print a["a"]}'
abc
[root@proxy mnt]# cat abc 以abc作为素材
abc
abc
xyz
opq
xyz
abc
在逐行任务中定义数组a++,for循环遍历数组a,显示下标:
[root@proxy mnt]# awk '{a[$1]++}END{for(i in a){print i}}' abc
opq
abc
xyz
逐行任务,相当于收集数据,然后在END任务中用for循环查看数组的所有内容:
[root@proxy mnt]# awk '{a[$1]++}END{for(i in a){print i,a[i]}}' abc
opq 1
abc 3
xyz 2
以上结果解析:
abc (定义ABC下标) a[abc]=1 (统计次数为1次)
abc (已有ABC下标) a[abc]=2 (统计次数为2次)
xyz (定义xyz下标) a[xyz]=1 (统计次数为1次)
opt (定义opt下标) a[opt]=1 (统计次数为1次)
abc (已有ABC下标) a[abc]=3 (统计次数为3次)
xyz (已有xyz下标) a[xyz]=2 (统计次数为2次)
abc下标的总数为3次
xyz下标的总数为2次
opt下标的总数为1次
[root@proxy mnt]# cat abc 以abc为素材
abc 192.168.0.1
abc 192.168.0.1
xyz 192.168.0.2
opq 192.168.0.3
xyz 192.168.0.2
abc 192.168.0.1
[root@proxy mnt]# awk '{ip[$2]++}END{for(i in ip){print i}}' abc
192.168.0.1
192.168.0.2
192.168.0.3
[root@proxy mnt]# awk '{ip[$2]++}END{for(i in ip){print i,ip[i]}}' abc
192.168.0.1 3
192.168.0.2 2
192.168.0.3 1
结果解析:
abc 192.168.0.1 (定义192.168.0.1为下标) a[192.168.0.1]=1 (统计次数为1次)
abc 192.168.0.1 (已有192.168.0.1下标) a[192.168.0.1]=2 (统计次数为2次)
xyz 192.168.0.2 (定义192.168.0.2为下标) a[192.168.0.2]=1 (统计次数为1次)
opt 192.168.0.3 (定义192.168.0.3为下标) a[192.168.0.3]=1 (统计次数为1次)
abc 192.168.0.1 (已有192.168.0.1下标) a[192.168.0.2]=2 (统计次数为3次)
xyz 192.168.0.2 (已有192.168.0.2下标) a[192.168.0.1]=3 (统计次数为2次)
192.168.0.1下标的总数为3次
192.168.0.2下标的总数为2次
192.168.0.3下标的总数为1次
利用sort对提取结果排序
sort 命令: 将文本文件内容加以排序,sort可针对文本文件的内容,以行为单位来排序。
- -b 忽略每行前面开始出的空格字符。
- -c 检查文件是否已经按照顺序排序。
- -d 排序时,处理英文字母、数字及空格字符外,忽略其他的字符。
- -f 排序时,将小写字母视为大写字母。
- -i 排序时,除了040至176之间的ASCII字符外,忽略其他的字符。
- -k 针对指定的列进行排序
- -m 将几个排序好的文件进行合并。
- -M 将前面3个字母依照月份的缩写进行排序。
- -n 依照数值的大小排序。是以数字形式排序
- -o <输出文件> 将排序后的结果存入指定的文件。
- -r 以相反的顺序来排序。是降序
- -t <分隔字符> 指定排序时所用的栏位分隔字符。
awk扩展应用
使用awk统计Web访问排名:
在分析Web日志文件时,每条访问记录的第一列就是客户机的IP地址,其中会有很多重复的IP地址。因此只用awk提取出这一列是不够的,还需要统计重复记录的数量并且进行排序。
通过awk提取信息时,利用IP地址作为数组下标,每遇到一个重复值就将此数组元素递增1,最终就获得了这个IP地址出现的次数。
下面以proxy虚拟机作为web服务端:由另外2台虚拟机作为测试机
[root@proxy ~]# rpm -q httpd
httpd-2.4.6-80.el7.centos.x86_64
[root@proxy ~]# systemctl restart httpd
[root@proxy ~]# ss -nutlp |grep :80
tcp LISTEN 0 128 *:80 *:* users:(("httpd",pid=1037,fd=3),("httpd",pid=1036,fd=3),("httpd",pid=1035,fd=3),("httpd",pid=1034,fd=3),("httpd",pid=1033,fd=3),("httpd",pid=1032,fd=3))
[root@proxy ~]# cd /var/log/httpd
[root@proxy httpd]# ls ##httpd服务的访问日志
access_log error_log
利用真机,其他虚拟机进行访问
[root@proxy ~]# curl localhost
[root@proxy ~]# curl 192.168.4.5
[root@proxy2 ~]# curl 192.168.4.5
[root@proxy2 ~]# curl 192.168.4.5
[root@proxy3 ~]# for i in {1..20}
> do
> curl 192.168.4.5
> done
查看网站的被访问次数,与对应的IP地址,然后降序排列:
[root@proxy httpd]# awk '{ip[$1]++}END{for(i in ip){print ip[i],i}}' /var/log/httpd/access_log | sort -nr
1 127.0.0.1
2 192.168.4.6
20 192.168.4.7
编写监控脚本
本案例要求编写脚本,实现计算机各个性能数据监控的功能,具体监控项目要求如下:
1.CPU负载
2.网卡流量
3.内存剩余容量
4.磁盘剩余容量
5.计算机账户数量
6.当前登录账户数量
7.计算机当前开启的进程数量
8.本机已安装的软件包数量
1.查看性能数据的命令
- 1.CPU负载 : [root@proxy ~]# uptime
- 2.网卡流量 : [root@proxy ~]# ifconfig eth0
- 3.内存剩余容量 : [root@proxy ~]# free
- 4.磁盘剩余容量 : [root@proxy ~]# df
- 5.计算机账户数量 : [root@proxy ~]# wc -l /etc/passwd
- 6.当前登录账户数量 : [root@proxy ~]# who |wc -l
- 7.计算机当前开启的进程数量 : [root@proxy ~]# ps aux | wc -l
- 8.本机已安装的软件包数量 : [root@proxy ~]# rpm -qa |wc -l
2.用awk进行处理1-5
- 1.[root@proxy mnt]# uptime | awk '{print "CPU的平均负载是"$8 $9 $10}' ##列数请参照实际情况,此为案例
- 2.[root@proxy mnt]# ifconfig eth0 |awk -F[\(\)] '/RX p/{print "eth0的接收流量是"$2}'
- 2.[root@proxy mnt]# ifconfig eth0 |awk -F[\(\)] '/TX p/{print "eth0的接收流量是"$2}'
- 3.[root@proxy mnt]# free -m | awk '/Mem:/{print "当前主机剩余内存空间"$4"MB"}'
- 4.[root@proxy mnt]# df -h |awk '/\/$/{print "主机根分区剩余空间是"$4}'
- 5.[root@proxy mnt]# awk 'END{print "本机账户数量是"NR"个"}' /etc/passwd |wc -l
3.编写监控脚本
[root@proxy mnt]# vim test09.sh
#!/bin/bash
#这是一个简单的监控测试脚本
while :
do
uptime | awk '{print "CPU的平均负载是"$8 $9 $10}'
ifconfig eth0 |awk -F[\(\)] '/RX p/{print "eth0的接收流量是"$2}'
ifconfig eth0 |awk -F[\(\)] '/TX p/{print "eth0的发送流量是"$2}'
free -m | awk '/Mem:/{print "当前主机剩余内存空间"$4"m"}'
df -h |awk '/\/$/{print "主机根分区剩余空间是"$4}'
awk 'END{print "本机账户数量是"NR"个"}' /etc/passwd
u=`who | wc -l`
echo "主机账户数量是$u个"
p=`ps aux | wc -l`
echo "当前主机开启的进程数量是$p个"
r=`rpm -qa | wc -l`
echo "当前主机已安装的软件包的数量是$r个"
sleep 3
clear ##清屏,效果跟Ctrl+l相同
done
[root@proxy mnt]# bash test09.sh
CPU的平均负载是0.14,0.05,0.05
eth0的接收流量是947.0 KiB
eth0的发送流量是922.1 KiB
当前主机剩余内存空间1184m
主机根分区剩余空间是29G
当前主机用户数量是31个
当前主机登录账户数量是2个
当前主机开启的进程数量是93个
当前主机已安装的软件包的数量是440个
编写安全检测脚本
防止远程ssh暴力破解密码,具体监控项目要求如下:
- 检测ssh登录日志,如果远程登陆账号名错误3次,则屏蔽远程主机的IP
- 检测ssh登录日志,如果远程登陆密码错误3次,则屏蔽远程主机的IP
1.过滤帐户名失败的命令(登陆日志文件为/var/log/secure)
- [root@proxy mnt]# awk '/Invalid user/{print $11}' /var/log/secure ##列出登录失败的账号
- [root@proxy mnt]# awk '/Invalid user/{ip[$11]++}END{for(i in ip){print ip[i],i}}' /var/log/secure ##统计次数
2. 过滤密码失败的命令
- [root@proxy mnt]# awk '/Failed/{print $11}' /var/log/secure ##列出密码登录失败的账号
- [root@proxy mnt]# awk '/Failed/{ip[$11]++}END{for(i in ip){print ip[i],i}}' /var/log/secure ##统计次数
3.编写安全检测脚本
[root@proxy mnt]# vim a.sh
#!/bin/bash
#这是一个简单的安全检测脚本
p=`awk '/Failed/{ip[$11]++}END{for(i in ip){print ip[i],i}}' /var/log/secure |awk '$1>3{print $2}'`
[ -z "$p" ] || echo "有人尝试登录服务器!!!!相关信息是$p" | mail -s test root