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