awk模式

awk模式

  • BEGIN/END模式
  • 关系表达式模式
  • 空模式
  • 正则模式
  • 行范围模式

模式也可以理解为条件。不指定任何”条件”,awk会一行一行的处理文本中的每一行。指定了”条件”,只有满足”条件”的行才会被处理,不满足”条件”的行就不会被处理。

关系表达式模式

关系运算符 含义 用法示例
< 小于 x < y
<= 小于等于 x <= y
== 等于 x == y
!= 不等于 x != y
>= 大于等于 x >= y
> 大于 x > y
~ 与对应的正则匹配则为真 x ~ /正则/
!~ 与对应的正则不匹配则为真 x !~ /正则/
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
[root@bogon ~]# cat test
abc 345 ssd asdf lkj;l
123 klj adf daff adeills adsfei
[root@bogon ~]# awk 'NF==5 {print $0}' test
abc 345 ssd asdf lkj;l
# 打印正好有五列的行。这里的条件就是这一行一共有五列

[root@bogon ~]# awk 'NF>2{print $0}' test
abc 345 ssd asdf lkj;l
123 klj adf daff adeills adsfei
[root@bogon ~]# awk 'NF<=4 {print $0}' test
# 文件中没有小于等于四列的行
[root@bogon ~]# awk '$1==123 {print $0}' test
123 klj adf daff adeills adsfei
# 一定要用两个等号

空模式

1
2
3
4
[root@bogon ~]# awk '{print $0}' test
abc 345 ssd asdf lkj;l
123 klj adf daff adeills adsfei
# 没有使用模式实际是使用的空模式,"空模式"会匹配文本中的每一行,所以,每一行都满足"条件"
打印奇偶行
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
[root@bogon ~]# cat test9
1
2
3
4
5
6
7
8
9
10
11
12
[root@bogon ~]# awk 'i=!i' test9
1
3
5
7
9
11
[root@bogon ~]# awk '!(i=!i)' test9
2
4
6
8
10
12
# 当awk开始处理第一行时,变量 i 被初始化,变量 i 在被初始化时,值为"空",而awk中,数字0或者"空字符串"表示假,所以可以认为模式为假,但是 i 直接取反了,对假取反后的值为真,将取反后的值又赋值给了变量i,此刻,变量i的值为真,所以当awk处理第一行文本时,变量i的值被赋值为真,模式成立则需要执行对应的动作,而上例中又省略了动作,所以默认动作为"{print $0}",所以,第一行被整行打印了。当第一行文本处理完毕后,awk开始处理第二行文本,此时,i 为真,但是取反后,i 为假,所以第二行没有被输出,依次类推,最终只打印了奇数行。打印偶数行同理,只是从第一次就让i为空字符串为假
* 知识点
# 在awk中,如果省略了模式对应的动作,当前行满足模式时,默认动作为打印整行,即{print $0}。
# 在awk中,0或者空字符串表示"假",非0值或者非空字符串表示"真"

* 解析
[root@bogon ~]# awk '/1/{print $0}' test9
1
10
11
12
# 如果当前行中包含字符"1",则执行对应的动作,而对应的动作就是打印整行。
root@ccjd:~# awk '/regi/&&/mi/&&/192/{print $0}' daemon.json | head
"registry-mirrors":["http://192.168.0.198:80"],
# 也可以通过&&符号指定多个条件,需要同时满足才可以。
[root@bogon ~]# awk '$1>10{print $0}' test9
11
12
# 如果test9文本中文本行的第一列的值如果大于10,则打印整行。
[root@bogon ~]# awk '/1/' test9
1
10
11
12
[root@bogon ~]# awk '$1>10' test9
11
12
# 当使用了模式时,如果省略了模式对应的动作,默认动作为"{print $0}""空模式""BEGIN/END模式"除外。

[root@bogon ~]# cat test2
hey
heey
heeey
heeeey
[root@bogon ~]# awk '{print $0}' test2
hey
heey
heeey
heeeey
[root@bogon ~]# awk '1{print $0}' test2
hey
heey
heeey
heeeey
[root@bogon ~]# awk '2{print $0}' test2
hey
heey
heeey
heeeey
[root@bogon ~]# awk '2' test2
hey
heey
heeey
heeeey
[root@bogon ~]# awk '0{print $0}' test2
[root@bogon ~]# awk '0' test2
# 第一条awk命令使用了"空模式",也就是说,每一行都满足模式,每一行经过"空模式"匹配以后结果都是"真",所以每一行都会执行对应的动作。第二条awk命令原来"模式的位置"被替换为了数字"1",我们可以把数字"1"理解成一种模式匹配后的结果,而1是非零值,在awk中非零值表示真,所以,"1"表示"真", 换句话说就是模式的匹配结果为真,模式成立则会执行对应的动作,也就是打印整行。第三条awk命令与第二条awk命令同理,动作前的数字可以换为任何非0数字或非空字符串。第四条awk命令数字"2"为非零值,表示模式为真,当使用模式时,可以省略动作,当使用模式并省略动作时,默认动作为打印整行,所以,第四条awk命令表示打印所有行,因为每一行的模式都为真。第五条awk命令与第六条awk命令因为数字"0"与空字符串表示假,当模式为假时,不会执行对应的动作,而当存在模式并省略动作时,默认动作为打印整行,但是由于模式为假,所以对应的动作并未执行。
# 理解了此处,再看上面打印奇偶行就容易理解了
[root@bogon ~]# awk '!0' test2
hey
heey
heeey
heeeey
[root@bogon ~]# awk '!5' test2
# 还能对真与假进行取反,非真即为假,非假即为真
[root@bogon ~]# awk 'i=1' test2
hey
heey
heeey
heeeey
[root@bogon ~]# awk 'i=a' test2
[root@bogon ~]# awk 'i="a"' test2
hey
heey
heeey
heeeey
[root@bogon ~]# awk 'i=0' test2
[root@bogon ~]# awk 'i=""' test2
# 使用了awk的变量,将变量 i赋值为1,当 i=1 以后,i为非零值,表示为真,我们可以认为这是一种模式匹配后的结果,当模式为真时,同时省略了对应动作时,默认动作为打印整行,所以上例会输出test2中的所有行。

[root@bogon ~]# awk '{i=!i;print i}' test2
1
0
1
0
# 打印出处理每一行时,i 对应的值。

正则模式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
# "正则表达式"当做"条件",能与正则匹配的行,就算满足条件,满足条件的行才会执行对应的动作,不能被正则匹配到的行,则不会执行对应的动作。

语法
awk '/正则表达式/{动作}' 文件

[root@bogon ~]# grep "^ruo" /etc/passwd
ruopu:x:1000:1000::/home/ruopu:/bin/bash
[root@bogon ~]# awk '/^ruo/{print $0}' /etc/passwd
ruopu:x:1000:1000::/home/ruopu:/bin/bash

[root@bogon ~]# awk -F":" 'BEGIN{printf "%-10s%-10s\n","用户名","用户ID"} /^ruo/{printf "%-10s\t%-10s\n",$1,$3}' /etc/passwd
用户名 用户ID
ruopu 1000
# 从/etc/passwd文件中找出符合条件的行(用户名以ruo开头的用户);找出符合条件的文本行以后,以":"作为分隔符,将文本行分段;取出我们需要的字段,格式化输出;结合BEGIN模式,输出一个格式化以后的文本,提高可读性

[root@bogon ~]# grep "/bin/bash" /etc/passwd
root:x:0:0:root:/root:/bin/bash
ruopu:x:1000:1000::/home/ruopu:/bin/bash
[root@bogon ~]# awk '/\/bin\/bash/{print $0}' /etc/passwd
root:x:0:0:root:/root:/bin/bash
ruopu:x:1000:1000::/home/ruopu:/bin/bash
# 使用斜线时要用转义符
# 当在awk命令中使用正则模式时,使用到的正则用法属于"扩展正则表达式"

[root@bogon ~]# awk -V
GNU Awk 4.0.2
# CentOS7使用awk版本
[root@bogon ~]# cat test2
hey
heey
heeey
heeeey
[root@bogon ~]# awk '/he{2,3}y/{print $0}' test2
heey
heeey
# CentOS7中可以直接使用{x,y}的形式匹配
[root@bogon ~]# awk --posix '/he{2,3}y/{print $0}' test2
heey
heeey
[root@bogon ~]# awk --re-interval '/he{2,3}y/{print $0}' test2
heey
heeey
# 如果无法直接使用{x,y}的形式,就要使用--posix或者--re-interval选项

行范围模式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
* 语法
awk '/正则1/,/正则2/{动作}' 文件
# 从被正则1匹配到的行开始,到被正则2匹配到的行结束,之间的所有行都会执行对应的动作。在行范围模式中,不管是正则1,还是正则2,都以第一次匹配到的行为准

[root@bogon ~]# cat -n test4
1 Allen Phillips
2 Green Lee
3 William Aiden James Lee
4 Angel Jack
5 Tyler Kevin
6 Lucas Thomas
7 Kevin
[root@bogon ~]# awk '/Lee/,/Kevin/{print $0}' test4
Green Lee
William Aiden James Lee
Angel Jack
Tyler Kevin
# 找出从Lee第一次出现的行,到Kevin第一次出现的行之间的所有行

[root@bogon ~]# awk 'NR>=3 && NR<=6 {print $0}' test4
William Aiden James Lee
Angel Jack
Tyler Kevin
Lucas Thomas
# 这样也可以打印出需要范围的行

* 关系运算符~与!~的使用
[root@bogon ~]# cat test3
主机名 网卡1的IP 网卡2的IP
主机A 192.168.1.123 192.168.1.124
主机B 192.168.2.222 172.16.100.3
主机C 10.1.0.1 172.16.100.3
主机D 10.1.2.1 192.168.1.15
主机E 10.1.5.1 172.16.100.5
主机F 192.168.1.234 172.16.100.6
主机G 10.1.7.1 172.16.100.7
[root@bogon ~]# awk '$2~/192\.168\.[0-9]{1,3}\.[0-9]{1,3}/{print $1,$2}' test3
主机A 192.168.1.123
主机B 192.168.2.222
主机F 192.168.1.234
# 找出网卡1的IP地址在192.168.0.0/16网段内的主机。先执行第二列匹配相应地址,最后再打印出来。如果正则模式不能使用,要加入--posix或者--re-interval选项
作者

John Doe

发布于

2018-10-17

更新于

2023-03-17

许可协议