1、awk 实例

1.1、判断磁盘已用空间超过 80%的 Filesystem

[root@fangcunshan ~]# df -hT
Filesystem                                     Type      Size  Used Avail Use% Mounted on
devtmpfs                                       devtmpfs  252G     0  252G   0% /dev
tmpfs                                          tmpfs     252G   16K  252G   1% /dev/shm
tmpfs                                          tmpfs     252G  2.3G  250G   1% /run
tmpfs                                          tmpfs     252G     0  252G   0% /sys/fs/cgroup
/dev/sdb2                                      xfs       184G  9.1G  175G   5% /
/dev/sdb1                                      xfs        10G  174M  9.9G   2% /boot
/dev/mapper/centos-home                        xfs        11T   86G   11T   1% /home
tmpfs                                          tmpfs      51G     0   51G   0% /run/user/0

# 获取 block device 类型包含 btrfs|ext2|ext3|ext4|reiser|xfs|ffs|ufs|jfs|jfs2|vxfs|hfs|apfs|refs|ntfs|fat32|zfs 的filesystem 并输出符合条件的整行数据
[root@fangcunshan ~]# df -hT |awk '{if($2 ~ /btrfs|ext2|ext3|ext4|reiser|xfs|ffs|ufs|jfs|jfs2|vxfs|hfs|apfs|refs|ntfs|fat32|zfs/) print $0}'
/dev/sdb2                                      xfs       184G  9.1G  175G   5% /
/dev/sdb1                                      xfs        10G  174M  9.9G   2% /boot
/dev/mapper/centos-home                        xfs        11T   85G   11T   1% /home

disk_space=$(df -hT |awk '{if($2 ~ /btrfs|ext2|ext3|ext4|reiser|xfs|ffs|ufs|jfs|jfs2|vxfs|hfs|apfs|refs|ntfs|fat32|zfs/) print $0}')
# 然后将返回的数据再做处理,使用 split 去掉不想要的字符串,例如我需要去掉前面的 Use% 该列的 % ,那么我们来分析一下使用shell来解决的思路,grep和sed命令都是针对整行的内容进行提取的,因此无法对一行中的某个字段的内容进行修改,因此我们使用awk来解决这个问题,awk中有一些内置的方法,这里使用split来拆分字段,split()接收三个参数,第一个参数是字段,第二个参数是拆分后的数组名称,最后一个参数是separator分隔符,这里我将分隔符设置为 % ,然后提取数组的第一个元素,这里需要注意的是数组是从1开始的,因此我们应该使用a[1]来提取后面的数字,将使用率超过80的输出,那么解决的代码如下所示:
echo "$disk_space" |awk '{split($6,a,"%");if(a[1]>=80) printf "Filesystem Name: %s\nUsed: %s\nFilesystem Type: %s\n\n", $NF,$(NF-1),$2}'

1.2、awk 统计文件中某一列中单词出现的次数

root@sse-lab-ci-002:~# cat /var/log/auth.log |grep sshd |grep from
May  1 01:01:38 sse-lab-ci-002 sshd[12697]: Failed password for root from 10.12.101.221 port 55654 ssh2
May  2 01:01:41 sse-lab-ci-002 sshd[11872]: Failed password for root from 10.12.101.221 port 38444 ssh2
May  3 01:01:48 sse-lab-ci-002 sshd[29264]: Failed password for root from 10.12.101.221 port 40784 ssh2
May  4 01:01:47 sse-lab-ci-002 sshd[24433]: Failed password for root from 10.12.101.221 port 33116 ssh2
May  5 01:01:49 sse-lab-ci-002 sshd[22210]: Failed password for root from 10.12.101.221 port 36474 ssh2
May  6 01:01:51 sse-lab-ci-002 sshd[24089]: Failed password for root from 10.12.101.221 port 45094 ssh2
May  6 10:05:27 sse-lab-ci-002 sshd[6402]: Accepted publickey for root from 10.12.111.138 port 49450 ssh2: RSA SHA256:LKK+bNYgGb5SspM0bq6CySdiOfT0mNJy15LkXin19lg


# 利用 awk 数组统计 auth.log 文件中 IP 出现的次数
root@sse-lab-ci-002:~# cat /var/log/auth.log |grep sshd |grep from |awk '{ip_list[$11]++}END{for (ip in ip_list) print ip,ip_list[ip]}'
10.12.111.138 1
10.12.101.221 6


# awk 统计过去 auth.log 文件中过去 10 分钟内登录的主机
# 注意,awk 里使用的 date -d 命令由于 -d 里有空格,所以将该命令执行的结果赋值给 unix 变量,并在最后 close(unix),原因是当前主机的 open files 只有 1024 ,在不更改 open files 大小的情况下,可以使用一个变量来接收 date 命令传递的结果,并在 awk 最后close()该变量,如果 date -d 里只有一个值是不需要赋值给变量的,例如 "date -d \""$1"\" +%s" ;

# 如果不想这么麻烦,可以直接修改 open files 的限制,ulimit -a 

root@sse-lab-ci-002:~# nowTS=$(date +%s)
root@sse-lab-ci-002:~# tail -c 500k /var/log/auth.log 2> /dev/null |grep sshd |grep from |awk -v durationTime=60000 -v nowTS="$nowTS" '{unix="date -d \""$1" "$2" "$3"\" +%s";unix|getline ts;close(unix);if((nowTS-ts)<durationTime) ip_list[$11]++}END{for (ip in ip_list) print ip,ip_list[ip]}'
10.12.31.101 1


# awk 统计过去 auth.log 文件中过去 10 分钟内登录超过 5次 的主机
root@sse-lab-ci-002:~# nowTS=$(date +%s)
root@sse-lab-ci-002:~# tail -c 500k /var/log/auth.log 2> /dev/null |grep sshd |grep from |awk -v durationTime=600 -v nowTS="$nowTS" '{unix="date -d \""$1" "$2" "$3"\" +%s";unix|getline ts;close(unix);if((nowTS-ts)<durationTime) ip_list[$11]++}END{for (ip in ip_list) if(ip_list[ip]>=1) print ip}'
10.12.31.101