跳到主要内容

awk匹配模式

1.正则表达式

1.1 匹配记录(整行)

匹配 /etc/passwd 文件中以 root 开头的

$ awk '/^root/' /etc/passwd
root:x:0:0:root:/root:/bin/bash

$ awk '$0 ~/^root/' /etc/passwd
root:x:0:0:root:/root:/bin/bash

1.2 匹配字段 匹配操作符(|!)

匹配 /etc/passwd 文件中第一列以 root 开头的

$ awk '$1~/^root/' /etc/passwd
root:x:0:0:root:/root:/bin/bash

匹配 /etc/passwd 文件中最后一列不是以 bash 结尾的

$ awk '$NF !~ /bash$/' /etc/passwd|head -5
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

^和~用法示例

提示

^ 在awk中表示以 ... 开头的列,在sed、grep中表示以 ... 开头的行

^用法示例

文件内容如下

$ cat t.txt 
1 101,hehe,CEO
2 102,haha,CTO
3 103,xixi,COO
4 105,yy,CFO
5 106,xx,CIO
6 110,jjxx,COCO

示例:打印文件中以1开头的行

$ awk '/^1/{print}' t.txt 
1 101,hehe,CEO

~用法示例

文件内容如下

$ cat t1.txt 
zhang san 1234567 :550:100:175
li si 88883336 :155:90:201
wang wu 66666666 :250:60:50
zhao liu 67676798 :150:80:75
hao qi 11112222 :250:100:175
zhu ba 000098763 :50:95:135

显示所有ID号码最后一位是2或7的人的全名

$ awk '$3~/[27]$/{print $1,$2}' t1.txt
zhang san
hao qi

显示文件中第三列以1开头的行

$ awk '$3~/^1/{print}' t1.txt 
zhang san
hao qi

显示zhang的姓氏和ID号码

$ awk '$1~/zhang/{print $1,$3}' t1.txt 
zhang 1234567

显示zhang的捐款,每个值都以 $ 开头,如 $250$100$175

  • 方法一

    $ awk -vFS='[ :]+' -vOFS=$ '$1~/zhang/{print "$"$4,$5,$NF}' t1.txt 
    $550$100$175
  • 方法二

    :::tip说明

    awk替换函数gsub gsub 全局替换 awk内置命令(函数)

    使用方法

    gsub(//,"",$n)  n表示数字
    gsub(/找谁/,"替换为什么",替换哪一列)

    :::

    $ awk '$1~/zhang/{gsub(/:/,"$",$NF);print $1,$NF}' t1.txt 
    zhang $550$100$175

2.条件表达式

2.1 关系运算符

运算符含义
<小于
<=小于等于
==等于
!=不等于
>大于
>=大于等于
~模糊匹配
!~模糊匹配取反

2.2 示例

文件内容如下

$ cat t.txt 
1 101,hehe,CEO
2 102,haha,CTO
3 103,xixi,COO
4 105,yy,CFO
5 106,xx,CIO
6 110,jjxx,COCO

示例1:打印第一列大于3的行

$ awk '{if($1>3)print}' t.txt 
4 105,yy,CFO
5 106,xx,CIO
6 110,jjxx,COCO

示例2:显示磁盘使用率大于10%的磁盘分区和挂载点

$ df -h
Filesystem Size Used Avail Use% Mounted on
/dev/mapper/centos-root 17G 2.4G 15G 14% /
devtmpfs 224M 0 224M 0% /dev
tmpfs 236M 0 236M 0% /dev/shm
tmpfs 236M 9.6M 226M 5% /run
tmpfs 236M 0 236M 0% /sys/fs/cgroup
/dev/sda1 1014M 132M 883M 14% /boot
tmpfs 48M 0 48M 0% /run/user/0

$ df -h|awk -F'[% ]+' 'NR>1 && $5>10{print $1,$5"%",$NF}'
/dev/mapper/centos-root 14% /
/dev/sda1 14% /boot

示例3:计算内存使用率

  • centos6

    centOS6查看内存使用

    $ free -m
    total used free shared buffers cached
    Mem: 474 171 303 0 30 44
    -/+ buffers/cache: 95 378
    Swap: 1023 0 1023

    centOS6计算内存使用率

    $ free -m|awk 'NR==3{print $3/($3+$4)*100"%"}'
    20.296%
  • centos7

    Centos7查看内存使用

    $ free -m
    total used free shared buff/cache available
    Mem: 470 90 243 5 136 330
    Swap: 2047 0 2047

    Centos7计算内存使用率

    $ free -m|awk 'NR==2{print ($2-$NF)/$2*100"%"}'
    30%

示例4:同时计算内存使用率和空闲率

  • centos6

    centos6计算内存使用率和空闲率

    $ free -m|awk 'NR==3{print $3/($3+$4)*100"%",$NF/($3+$NF)*100"%"}'
    20.4641% 79.5359%
  • centos7

    centos7计算内存使用率和空闲率

    $ free -m|awk 'NR==2{print ($2-$NF)/$2*100"%",$NF/$2*100"%"}'
    30% 70%

2.3 awk的一个坑

:::caution注意

awk会把数字当成字符处理

:::

查看磁盘使用率

$ df -h
Filesystem Size Used Avail Use% Mounted on
/dev/sda3 19G 2.4G 16G 14% /
tmpfs 238M 0 238M 0% /dev/shm
/dev/sda1 190M 35M 146M 19% /boot

打印第二行第5列小于9的列,结果不正确

$ df -h|awk 'NR>1 && $5<9{print $1,$5,$NF}'
/dev/sda3 14% /
tmpfs 0% /dev/shm
/dev/sda1 19% /boot

因为awk会把数字当成字符处理,比如sort 如下所示,sort会把数字当成字符处理,并没有把数字从大到小排序

$ seq 15|sort
1
10
11
12
13
14
15
2
3
4
5
6
7
8
9

解决awk把数字当成字符处理问题的方法

  • 方法1 用指定分隔符的方式把数字和 % 分割开

    # 正确输出
    $ df -h|awk -F'[% ]+' '$5<9{print $1,$5,$NF}'
    tmpfs 0 /dev/shm

    # 不正确输出
    $ df -h|awk '$5<9{print $1,$5,$NF}'
    /dev/sda3 14% /
    tmpfs 0% /dev/shm
    /dev/sda1 19% /boot
  • 方法2 让awk知道进行数字比较,某一列加0

    # 正确输出
    $ df -h|awk 'NR>1 && $5+0<9{print $1,$5,$NF}'
    tmpfs 0% /dev/shm

    # 不正确输出
    $ df -h|awk 'NR>1 && $5<9{print $1,$5,$NF}'
    /dev/sda3 14% /
    tmpfs 0% /dev/shm
    /dev/sda1 19% /boot

3.运算表达式

示例1:打印 /etc/passwd 第三列与10相乘大于5000的内容

$ awk -F: '$3 * 10 > 5000' /etc/passwd
polkitd:x:999:998:User for polkitd:/:/sbin/nologin
chrony:x:998:996::/var/lib/chrony:/sbin/nologin
mysql:x:1000:1000::/home/mysql:/sbin/nologin

示例2:打印 /etc/passwd 第三列与10相乘大于500的内容,并打印第一列和第三列

$ awk -F: 'BEGIN{OFS="--"} { if($3*10>5000) {print $1,$3} } END {print "打印ok"}' /etc/passwd
polkitd--999
chrony--998
mysql--1000
打印ok

示例3:加、减、乘、除、取模、幂运算

文件内容如下

$ cat test.txt 
a 1 2 3 4 5
b 1 2 3 4 5
a 5 6 7 8 9

加法计算

$ awk '/a/{print $2+10}' test.txt 
11
15

减法计算

$ awk '/a/{print $2-10}' test.txt 
-9
-5

乘法计算

$ awk '/a/{print $2*10}' test.txt 
10
50

除法计算

$ awk '/a/{print $2/10}' test.txt 
0.1
0.5

取模计算

$ awk '/a/{print $2%10}' test.txt 
1
5

幂计算

$ awk '/a/{print $2**10}' test.txt 
1
9765625

4.逻辑操作符和复合模式

4.1 逻辑操作符

符号含义
&&逻辑与
||逻辑或
逻辑非

示例1:打印 /etc/passwd 文件中用户名为 root 并且打印 uid 小于15的行

# 文件中第三列是UID
$ awk -F: '$1~/root/ && $3<=1' /etc/passwd
root:x:0:0:root:/root:/bin/bash

示例2:打印用户名为 root 或第三列大于500的行

$ awk -F: '$1~/root/ || $3>=500' /etc/passwd
root:x:0:0:root:/root:/bin/bash
polkitd:x:999:998:User for polkitd:/:/sbin/nologin
chrony:x:998:996::/var/lib/chrony:/sbin/nologin
mysql:x:1000:1000::/home/mysql:/bin/false

4.2 三元运算符

三元运算符表达式

三元运算符的形式1:[ 结果 = 条件 ? 结果1 :结果2 ]

三元运算符的形式2:[ 条件 ? 表达式1 : 表达式2 ]

示例:

文件内容如下

$ cat t.txt 
student1 98
student2 99
student3 93
student4 78
student5 85

根据学生成绩判断学生成绩是否为优秀,这里规定分数大于90是优秀,低于90非优秀

  • 非三元运算写法

    $ awk '{if($2>90){print $1,"优秀"}else{print $1,"不优秀"}}' t.txt 
    student1 优秀
    student2 优秀
    student3 优秀
    student4 不优秀
    student5 不优秀
  • 三元运算写法

    • 写法1 结果 = 条件 ? 结果1:结果2

      $ awk '{res=$2>90?"优秀":"不优秀";print $1,res}' t.txt 
      student1 优秀
      student2 优秀
      student3 优秀
      student4 不优秀
      student5 不优秀

      # 上述awk写法中的print也可以单独写在一个大括号中
      awk '{res=$2>90?"优秀":"不优秀"}{print $1,res}' t.txt
    • 写法2 条件 ? 表达式1 :表达式2

      # a表示符合条件的,b表示不符合条件的,大于90分的有3个,低于90分的有2个
      $ awk '{$2>90?a++:b++}END{print a,b}' t.txt
      3 2

风骚走位!!!

文件内容

$ cat lessons.txt 
634751 预排
568688 预排
386760 删除
619373 预排
428491 预排
487563 完成
603342 完成
436339 完成
结果:
删除 386760
完成 487563,603342,436339
预排 634751,568688,619373,428491

啥意思?

# 方法1
$ awk '{a[$2]=a[$2]?a[$2]","$1:a[$2]$1}END{for(i in a) print i,a[i]}' lessons.txt
删除 386760
完成 487563,603342,436339
预排 634751,568688,619373,428491

# 方法2
$ awk '{if(a[$2]){a[$2]=a[$2]","$1}else{a[$2]=a[$2]$1}}END{for(i in a) print i,a[i]}' lessons.txt
删除 386760
完成 487563,603342,436339
预排 634751,568688,619373,428491

啥意思?

$ awk '{a[$2]=a[$2]","$1}END{for(i in a) print i,a[i]}' lessons.txt
删除 ,386760
完成 ,487563,603342,436339
预排 ,634751,568688,619373,428491