【Linux系列教程】awk工具

一、关于awk工具

  • 工作流程
    • 默认情况下,awk可以使用空白字符分割文本, awk内部可以分别$1, $2变量代表第一段内容
    • -F选项指定分割符
    • 逐行处理
  • 作用
  • 显示文本

二、awk基本命令格式

# awk [option] 'script' 文件名称  文件名称 

# awk [option] 'PATTERN{action}'  文件名称  文件名称

常用action

  • print
  • printf

1.print操作

[root@master ~]# sed -n '1p' /etc/passwd	#显示第一行
root:x:0:0:root:/root:/bin/bash
[root@master ~]# sed -n '1p' /etc/passwd | awk -F: '{print $1}'		#使用管道符处理上一个命令的结果,以":"为分隔符,显示第一个字段
root
[root@master ~]# sed -n '1p' /etc/passwd | awk -F: '{print $1,$7}'	#以":"为分隔符,显示第一个字段和第七个字段
root /bin/bash
[root@master ~]# sed -n '1p' /etc/passwd | awk -F: '{print $0}'		#特殊$0查看一整字段
root:x:0:0:root:/root:/bin/bash

支持自定义输出

awk '{print "自定义字段"$显示的字段数}'
[root@master ~]# sed -n '1p' /etc/passwd | awk -F: '{print "用户名:"$1,"终端:"$7}'
用户名:root 终端:/bin/bash

2.printf操作

  • 格式化输出内容
  • 使用格式
    • printf “格式格式”,内容,内容
    • 占位符
      • %s 字符串
      • %d 整数
      • %f 浮点数
[root@master ~]# sed -n 'p' /tmp/passwd | awk -F: '{print $1,$6}'	#没有用printf格式化处理之前
root /root
bin /bin
daemon /sbin
adm /var/adm
lp /var/spool/lpd
sync /sbin
[root@master ~]# sed -n 'p' /tmp/passwd | awk -F: '{printf "%-10s%s\n", $1,$6}'
root      /root
bin       /bin
daemon    /sbin
adm       /var/adm
lp        /var/spool/lpd
sync      /sbin

%s代表字符串,中间数字10,设置字符宽度为10-修改默认右对齐为左对齐,\n为换行符

[root@master ~]# sed -n 'p' /tmp/passwd | awk -F: '{printf "%10s%s\n", $1,$6}'	#如果不添加“-”就会默认右对齐
      root/root
       bin/bin
    daemon/sbin
       adm/var/adm
        lp/var/spool/lpd
      sync/sbin
[root@master ~]# sed -n 'p' /tmp/passwd | awk -F: '{printf "%-10s%s", $1,$6}'
root      /rootbin       /bindaemon    /sbinadm       /var/admlp        /var/spool/lpdsync      /sbin[root@master ~]# 
#可以看到没有\n换行输出的结果,和命令提示符连在一起了,格式很乱

因为我们新增自定义字符,所以前面%s要多加2个用来控制那2个字符的格式

[root@master ~]# sed -n 'p' /tmp/passwd | awk -F: '{printf "%s%-10s%s%s\n", "用户名:",$1, "默认终端:",$7}'
用户名:root      默认终端:/bin/bash
用户名:bin       默认终端:/sbin/nologin
用户名:daemon    默认终端:/sbin/nologin
用户名:adm       默认终端:/sbin/nologin
用户名:lp        默认终端:/sbin/nologin
用户名:sync      默认终端:/bin/sync

同样可以控制我们自定义字符的宽度

[root@master ~]# sed -n 'p' /tmp/passwd | awk -F: '{printf "%-5s%-10s%-6s%s\n", "用户名:",$1, "默认终端:",$7}'
用户名: root      默认终端: /bin/bash
用户名: bin       默认终端: /sbin/nologin
用户名: daemon    默认终端: /sbin/nologin
用户名: adm       默认终端: /sbin/nologin
用户名: lp        默认终端: /sbin/nologin
用户名: sync      默认终端: /bin/sync

3.awk常用内置变量

FS

相当于-F选项的作用
保存行分割符,默认空白

[root@master ~]# sed -n 'p' /tmp/passwd | awk -v FS=":" '{print $1,$7}'
root /bin/bash
bin /sbin/nologin
daemon /sbin/nologin
adm /sbin/nologin
lp /sbin/nologin
sync /bin/sync

-F参数作用一样,都是已:为分隔符

[root@master ~]# sed -n 'p' /tmp/passwd | awk -F: '{print $1,$7}'
root /bin/bash
bin /sbin/nologin
daemon /sbin/nologin
adm /sbin/nologin
lp /sbin/nologin
sync /bin/sync

OFS

指定awk显示多段内容时,多段内容间的分隔符(自定义分隔符)
默认空白字符

[root@master ~]# sed -n 'p' /tmp/passwd | awk -F: -v OFS="---->" '{print $1,$7}'
root---->/bin/bash
bin---->/sbin/nologin
daemon---->/sbin/nologin
adm---->/sbin/nologin
lp---->/sbin/nologin
sync---->/bin/sync

NR

记录行号
处理多个文件时,所有文件的行号是连续记录的

[root@master ~]# awk '{print NR}' /etc/hosts /etc/fstab
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
[root@master ~]# awk 'NR==3{print $0}' /etc/passwd
daemon:x:2:2:daemon:/sbin:/sbin/nologin	#指定显示的行

FNR

记录行号
处理多个文件时,所有文件的行号是独立记录的

[root@master ~]# awk '{print FNR}' /etc/hosts /etc/fstab
1
2
3
4
1
2
3
4
5
6
7
8
9
10
11

NF

记录awk分割行后的段数

[root@master ~]# awk -F: '{print $NF}' /etc/passwd
/bin/bash
/sbin/nologin
/sbin/nologin
/sbin/nologin
/sbin/nologin
/bin/sync
/sbin/shutdown
/sbin/halt
[root@master ~]# cat /tmp/file01 
centos redhat
debian ubuntu Kubuntu Xubuntu
WindowsXP Windows7 Windows8 Windows8.1 Windows10 Windows11
MacOS
[root@master ~]# awk '{print $NF}' /tmp/file01
redhat
Xubuntu
Windows11
MacOS

FILENAME

保存awk正在处理的文件名

[root@localhost ~]# awk '{print FILENAME}' /tmp/file01
/tmp/file01
/tmp/file01
/tmp/file01
/tmp/file01

uniq去重

[root@master ~]# awk '{print FILENAME}' /tmp/file01 | uniq
/tmp/file01

4.awk自定义变量

awk -v 自定义变量名="值"
[root@master ~]# awk -v name="wsjj" '{print "hello", name}' /etc/fstab
hello wsjj
hello wsjj
hello wsjj
hello wsjj
hello wsjj
hello wsjj
hello wsjj
hello wsjj
hello wsjj
hello wsjj
hello wsjj

三、awk常用文本处理模式

1.表达式

  • 比较运算符
    • ==, >, >=, <, <=, !=
    • 数据 ~ 正则表达式
      • 判断数据是否可以被正则表达式
    • 数据 !~ 正则表达式
  • 逻辑运算符
    • && 并且
    • || 或者
[root@master ~]# awk '{print $0}' /tmp/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

[root@master ~]# awk -F: '$3>=1 && $3<=999{print $1}' /tmp/passwd
bin
daemon
adm
lp
sync

2./正则表达式/

[root@master ~]# awk '/^\/dev/{print $0}' /etc/fstab	#“\”为转译符
/dev/mapper/centos-root /                       xfs     defaults        0 0
/dev/mapper/centos-swap swap                    swap    defaults        0 0
[root@master ~]# awk '/^root/{print $0}' /tmp/passwd
root:x:0:0:root:/root:/bin/bash

3./正则表达式/,/正则表达式/

[root@localhost ~]# awk '/Sep 26 09:02:30/,/Sep 26 09:18:04/{print $0}' /var/log/messages

/正则表达式匹配的字符或数字/

4.BEGIN{}

定义awk开始处理内容执行的操作

[root@master ~]# awk -F: 'BEGIN{print "----以下是用户和默认终端----"}{print $1,$7}' /tmp/passwd
----以下是用户和默认终端----
root /bin/bash
bin /sbin/nologin
daemon /sbin/nologin
adm /sbin/nologin
lp /sbin/nologin
sync /bin/sync

5.END{}

定义awk处理内容要执行的操作

[root@master ~]# awk -F: 'BEGIN{print "----以下是用户和默认终端----"}{print $1,$7}END{print "----结束----"}' /tmp/passwd
----以下是用户和默认终端----
root /bin/bash
bin /sbin/nologin
daemon /sbin/nologin
adm /sbin/nologin
lp /sbin/nologin
sync /bin/sync
----结束----
[root@master ~]# awk -v number=0 '{number++}END{print number}' /tmp/passwd
6	#可以看到文件有6行数据

四、awk条件判断

1.语法格式

if (条件) {操作}
if (条件) {操作} else {操作}
if (条件) {操作} else if (条件)

判断管理员与普通账户

[root@master ~]# awk -F: '{if($3==0) {print $1 "是管理员用户"} else {print $1 "是普通用 户"}' /tmp/passwd
root是管理员用户
bin是普通用户
daemon是普通用户
adm是普通用户
lp是普通用户
sync是普通用户

统计bash用户和nologin用户的数量

[root@master ~]# awk -F: -v bash_number=0 -v nologin_numer=0 '{if($7=="/bin/bash") {bash_number++} else if($7=="/sbin/nologin") {nologin_number++}}END{print "bash用户数",bash_number, "nologin用户数",nologin_number}' /etc/passwd
bash用户数 4 nologin用户数 18

五、循环

1.for循环

for(变量定义; 循环条件; 改变变量的值) {操作}
for(i=1; i<=10; i++)
[root@master ~]# awk -F: '{for(i=1;i<=7;i++){if(length($i)>=5) {print $i}}}' /tmp/passwd/root
/bin/bash
/sbin/nologin
daemon
daemon
/sbin
/sbin/nologin
/var/adm
/sbin/nologin
/var/spool/lpd
/sbin/nologin
/sbin
/bin/sync

六、数组

1.定义数组

[root@localhost ~]# awk 'BEGIN{test[1]="martin"; test[2]="robin"; test[3]="lz"; print test[2]}'
robin

2.获取数组中所有数据

[root@localhost ~]# awk 'BEGIN{test[1]="martin"; test[2]="robin"; test[3]="lz"; for(i=1; i<=3; i++) {print test[i]}}'
martin
robin
lz

3.数组支持任意数据作为下标

[root@localhost ~]# awk 'BEGIN{test["martin"]="北京"; test["robin"]="河北"; test["lz"]="天津"; print test["robin"]}'
河北
[root@localhost ~]# awk 'BEGIN{test["martin"]="北京"; test["robin"]="河北"; test["lz"]="天津"; for(i in test) {print test[i]}}'
河北
天津
北京

统计httpd的UV和PV

UV 用户访问量
PV 页面访问量

#  awk '{uv[$1]++}END{for(i in uv) {print i, uv[i]}}' access_log
#  awk '{pv[$7]++}END{for(i in pv) {print i, pv[i]}}' access_log

七、awk内置函数

1.split(字符串,数组,行分割符)

使用分割符分割字符串, 将分割后的字符串保存到指定数组

#  awk 'BEGIN{split("a-b-c", data, "-"); print data[1]}'
#  awk 'BEGIN{split("a-b-c", data, "-"); print data[2]}'
#  awk 'BEGIN{split("a-b-c", data, "-"); print data[3]}'

2.length(string)

返回string字符串的字符个数

#  awk 'BEGIN{print length("shell")}'

3.substr(string,start [,length])

string字符串中的子串,从start开始,取length个;start1开始计数

#  awk 'BEGIN{data=substr("hello",2, 3); print data}'

4.system(command)

支持在awk内部调用shell命令

#  awk 'BEGIN{system("ifconfig enp2s0")}'

5.systime()

返回系统当前时间

#  awk 'BEGIN{print systime()}'
#  awk 'BEGIN{now=systime(); print strftime("%F_%T", now)}'

6.tolower(string)

string中的所有字母转为小写

#  awk 'BEGIN{print tolower("aBcD")}'

7.toupper(string)

string中所有字母转换为大写

#  awk 'BEGIN{print toupper("aBcD")}'