awk

awk

  • awk:单行脚本
  • 核心 awk:取行
  • 核心 awk:取列
  • 核心 awk:混合取行取列
  • awk:统计功能
  • 未来:判断循环
  • 未来:数组

1、awk概述

四剑客 特点 擅长
find 查找文件 查找文件,与其他命令配合
grep/egrep 过滤 过滤速度最快
sed 过滤、取行、替换、删除 替换修改文件内容、取行
awk 过滤、取行、取列、统计计算、判断、循环... 取行、取列、统计计算
  • awk是一种语言,叫做单行脚本

1、格式

取出/etc/passwd中的第1行的第1列、第3列和最后一列

awk -F: NR==1{print $1,3,NF} ' /etc/passwd

awk -F: '条件{动作1;动作2...}' /etc/passwd

条件:找谁

动作:干啥

2、awk取行

1️⃣取出/etc/passwd中的第一行

NR:Number of Record 记录号、行号。也可以写大于几行,小于几行

{print $0}:输出整行内容,$0表示当前的内容

sh 复制代码
## 简写
[root@Ansible-server ~]# awk 'NR==1' /etc/passwd
root:x:0:0:root:/root:/bin/bash
## 完整写法
[root@Ansible-server ~]# awk 'NR==1{print $0}' /etc/passwd
root:x:0:0:root:/root:/bin/bash
[root@Ansible-server ~]# awk 'NR>=6{print $0}' /etc/passwd

2️⃣取/etc/passwd出2-5行的内容

&&:表示并且,and

||:表示或者,or

sh 复制代码
[root@Ansible-server ~]# awk 'NR>=2 && NR<=5{print $0}' /etc/passwd
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

3️⃣过滤出/etc/passwd文件中包含root或者nobody的行

sh 复制代码
[root@Ansible-server ~]# awk '/root|nobody/' /etc/passwd
root:x:0:0:root:/root:/bin/bash
operator:x:11:0:operator:/root:/sbin/nologin
nobody:x:65534:65534:Kernel Overflow User:/:/sbin/nologin
stap-server:x:155:155:Systemtap Compile Server:/opt/rh/gcc-toolset-11/root/var/lib/stap-server:/sbin/nologin

4️⃣从包含root的行开始输出到包含nobody的行,可以使用这个功能实现截取一个时间段的日志

sh 复制代码
[root@Ansible-server ~]# awk '/root/ , /nobody/' /etc/passwd
  • 小结

    • awk+NR:取出指定的行,指定范围的行

    • awk+//:过滤

    • awk+其他变量:用于精确过滤(讲完取列就可以使用)

      sh 复制代码
      [root@Ansible-server ~]# awk -F: '$3==0' /etc/passwd
      root:x:0:0:root:/root:/bin/bash

3、awk取列

1️⃣使用awk取出ls -lh的表示大小的列和最后一列

  • NF:表示有多少列
  • $NF:最后一列
sh 复制代码
[root@Ansible-server opt]# ls -lh | awk '{print $5,$9}'
[root@Ansible-server opt]# ls -lh | awk '{print $5,$NF}'
49 a.txt
4.0K mplayer
2.1K passwd
93 rh
12G rhel8.8.iso
74 sed.txt
[root@Ansible-server opt]# ls -lh | awk 'NR>1{print $5,$NF}' | column -t   
49    a.txt
4.0K  mplayer
2.1K  passwd
93    rh
12G   rhel8.8.iso
74    sed.txt
[root@Ansible-server opt]# echo 123 355 6667 87678 23 | awk '{print $(NF-1),$NF}'
87678 23

2️⃣取出/etc/passwd中第一列、第三列和第五列

-F:指定列之间的分隔符,如果不加-F则默认是空格,-F也支持正则指定分隔符

sh 复制代码
[root@Ansible-server opt]# awk -F: '{print $1,$3,$NF}' /etc/passwd | column -t

3️⃣指定复杂分隔符取出IP

⚠️在inet前有多个空格,对于awk,如果使用-F参数,每遇到一个空格就切一刀,因此为了实现把所有连续的空格作为一个整体一起切断,我们需要在正则匹配分隔符时加上+号。

sh 复制代码
[root@Ansible-server opt]# ip address show ens160 | awk 'NR==4' | awk '{print $2}' | awk -F'/' '{print $1}'
192.168.121.141
## 进行简化
[root@Ansible-server opt]# ip address show ens160 | awk 'NR==4' | awk -F'[ /]+' '{print $3}'
192.168.121.141
[root@Ansible-server opt]# ip address show ens160 | awk 'NR==4' | awk -F'inet |/24' '{print $2}'
192.168.121.141
  • 小结
    • 如果是空格、连续空格,直接使用awk取列即可
    • 其他情况使用-F指定分隔符,必要时加正则实现

4、awk取行取列

awk 格式 '条件{动作}'
🌟🌟🌟🌟🌟取行+取列 取IP地址

sh 复制代码
[root@Ansible-server opt]# ip address show ens160 | awk -F'[ /]+' 'NR==4{print $3}'
192.168.121.141

🌟🌟🌟🌟🌟对列的判断,取出/etc/passwd文件中第三列大于1000的行,取出这些行的第一列、第三列和最后一列

sh 复制代码
[root@Ansible-server opt]# awk -F: '$3>1000{print $1,$3,$NF}' /etc/passwd | column -t
nobody    65534  /sbin/nologin
xiaoli    1001   /bin/bash
xiaowang  1002   /bin/bash

同时也支持逻辑表达式和条件表达式

如果系统swap使用超过0则输出异常

  • 条件
    • 过滤出swap
    • 第三列,大于0
  • 动作
    • 输出"异常"
sh 复制代码
[root@Ansible-server ~]# free | awk 'NR==3 && $3>0 {print "异常"}'
# 找出能进行登陆的普通用户
root@moudle01[13:41:27]:/opt
$ awk -F: '$3>=1000&&/bash$/{print}' /etc/passwd
xu:x:1000:1000::/home/xu:/bin/bash
xuxuxu:x:1001:1001::/home/xuxuxu:/bin/bash

过滤出/etc/passwd第四列的数字是以0或1开头的行,输出第一列、第三列、第四列

🍃awk中通过~可以实现对某一列进行过滤

某一列中含有xxx内容:

  • ~ 表示包含的意思 $1 ~ /root/ 表示第一列中包含root
  • !~表示不包含
  • 之前^和$表示某一行的开头或者结尾
  • 在awk中因为awk可以取列,通过列可以过滤出一列中包含什么...过滤出一列中以xxxx开头或者结尾的行
sh 复制代码
[root@Ansible-server ~]# awk -F: '$4 ~ /^[01]/ {print $1,$3,$4}' /etc/passwd | column -t

5、awk统计和计算

awk进行统计有两类案例:

1️⃣类似于wc -l统计次数

2️⃣进行累加、求和

(1)、统计次数

统计/etc/passwd中的行数

使用awk进行行数统计

⚠️由于awk的执行过程是一行一行的读取,END后面的内容是要在所有的行都读取完成后在执行

sh 复制代码
[root@Ansible-server ~]# awk '{i=i+1} END{print i}' /etc/passwd
40

(2)、累加、求和

sh 复制代码
[root@Ansible-server ~]# seq 10 | awk '{sum=sum+$1}END{print sum}'
55

6、BEGIN和END

在文件读取开始之前执行1次:BEGIN

在文件读取开始之后执行1次:END

和文件本身读取了几行没有关系,

sh 复制代码
root@moudle01[11:04:43]:/script
$ awk 'BEGIN{print "你好"}' /etc/passwd
你好
root@moudle01[11:05:08]:/script
$ awk 'END{print "你好"}' /etc/passwd
你好
root@moudle01[11:06:52]:/script
$ awk 'BEGIN{print "你好"} END{print "完毕"}' /etc/passwd
你好
完毕
sh 复制代码
root@moudle01[11:30:31]:/opt
$ awk -F: 'BEGIN{print "用户名\tUID\t家目录"}{print $1,$3,$6}END{print "共有"NR"个用户"}' user | column -t
用户名       UID  家目录
root         0    /root
bin          1    /bin
daemon       2    /sbin
adm          3    /var/adm
lp           4    /var/spool/lpd
共有5个用户

7、awk数组和for结合

sh 复制代码
$ awk 'BEGIN{a=10;a=20;print a}'
20
$ awk 'BEGIN{a[1]=10;a[2]=20;print a[1]}'
10
$ awk 'BEGIN{a[1]=10;a[2]=20;print a[2]}'
20
$ awk 'BEGIN{a[1]=10;a[2]="aaa";print a[2],a[1]}'
aaa 10
$ awk 'BEGIN{a["sss"]=10;a[2]="aaa";print a[2],a["sss"]}'
aaa 10

利用awk数组处理文件信息,统计文件中的数据出现了几次

sh 复制代码
$ cat shu.txt 
abc
xyz
abc
root@moudle01[17:07:33]:/opt
$ awk '{a[$1]++}END{print a["abc"]}' shu.txt 
2
root@moudle01[17:07:42]:/opt
$ awk '{a[$1]++}END{print a["xyz"]}' shu.txt 
1

awk中的for循环

for(变量名 in 数组名){任务指令}

此时变量得到的是数组中的下标

sh 复制代码
root@moudle01[17:17:08]:/opt
$ awk '{a[$1]++}END{for(i in a){print i,a[i]}}' shu.txt 
opq 1
abc 3
xyz 2

root@moudle01[17:21:36]:/opt
$ awk '{a[$1]++}END{for(i in a){print i,"访问次数:",a[i]}}' /var/log/httpd/access_log | sort -rn -k 3| column -t
192.168.121.1    访问次数:  9
192.168.121.180  访问次数:  9
192.168.121.181  访问次数:  6
# sort的-k参数:按照第几列排序,默认是按照空格分

# 查看系统安全日志,查看有哪些IP登录错误
root@moudle01[17:24:09]:/opt
$ awk '/Failed password for root/{ip[$11]++}END{for(i in ip){print i,ip[i]}}' /var/log/secure |  sort -rn -k 2| column -t
192.168.121.181 1

6、awk总结

  • 核心:awk取行取列
  • 熟悉:awk对列比较大小
  • 熟悉:awk对列进行过滤计算
  • 难点:awk计算、求和