0%

Shell正则应用

Shell正则应用

什么是正则表达式

正则表达式regular expression, RE是一种字符模式,用于在查找过程中匹配指定的字符。

为什么要使用正则表达式

​ 在工作中,我们时刻面对着大量的日志,程序,以及命令的输出。迫切的需要过滤我们需要的一部分内容,甚至是一个字符串。比如: 现在有一个上千行的文件,我们仅需要其中包含”root”的行,怎么办? 此时就需要使用到正则表达式的规则来筛选想要的内容。

正则表达式注意事项

1
2
3
4
5
6
7
1.正则表达式应用非常广泛,存在于各种语言中,例如:php,python,java等。

2.正则表达式和通配符特殊字符是有本质区别的

3.要想学好grep、sed、awk首先就要掌握正则表达式。

4.注意正则神坑,中文符号。

正则表达式规则

正则表达式 描述
\ 转义符,将特殊字符进行转义,忽略其特殊意义
^ 匹配行首,^是匹配字符串的开始
$ 匹配行尾,$是匹配字符串的结尾
^$ 表示空行
.(点) 匹配换行符之外的任意单个字符
[ ] 匹配包含在[字符]之中的任意一个字符
[^] 匹配[^]之外的任意一个字符
[a-z] 匹配[]中指定范围内的任意一个字符
? 匹配其前面的字符1次或者0次
+ 匹配其前面的字符1次或者多次
***** 匹配其前面的字符0次或者多次
.* 表示所有
( ) 匹配表达式,创建一个用于匹配的字符串
{n} 匹配之前的项n次,n是可以为0的正整数
{n,} 之前的项至少需要匹配n次
{n,m} 指定之前的项至少匹配n次,最多匹配m次,n<=m
| 或者
特定字符 含义
[[:upper:]] 所有大写字母
[[:lower:]] 所有小写字母
[[:alpha:]] 所有字母
[[:digit:]] 所有数字
[[:alnum:]] 所有的字母和数字
[[:space:]] 空白字符,空白。
[[:punct:]] 所有标点符号

正则表达式之GREP文本过滤

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
#环境准备
[root@qls ~]# cat test.txt
I am qiuzengjia teacher!
I teach linux.
test

I like badminton ball ,billiard ball and chinese chess!
my blog is http://www.oldboyedu.blog.com
our site is http://www.increase93.com
my qq num is 1176495252.
not 117666649555252.

#过滤以m开头的行

[root@qls ~]# grep "^m" test.txt

#过滤以m为结尾的行

[root@qls ~]# grep "m$" test.txt

#排除空行, 并打印行号

[root@qls ~]# grep -vn "^$" test.txt

#匹配任意一个字符,不包括空行

[root@qls ~]# grep "." test.txt

#匹配所有内容

[root@qls ~]# grep ".*" test.txt

#过滤出以.为结尾的行

[root@qls ~]# grep "\.$" test.txt

#过滤出以m和n为开头的行

[root@qls ~]# grep "^[mn]" test.txt

#过滤出文件中不是以m或n或o开始的行

[root@qls ~]# egrep "^[^mno]" test.txt
[root@qls ~]# egrep -v "^[mno]" test.txt

#过滤出空行,并显示行号

[root@qls ~]# grep -n "^$" test.txt

#把文件中每个字母总共出现多少次统计出

[root@qls ~]# grep -o "[a-Z]" test.txt |sort |uniq -c|sort -rh

#把文件中每个单词总共出现多少次统计出

[root@qls ~]# egrep -o "[a-Z]+" test.txt |sort |uniq -c|sort -rh

#找出/etc/passwd文件中的两位数或三位数的行;

[root@qls ~]# grep -Ew "[0-9]{2,3}" /etc/passwd

#找出/proc/meminfo文件中,所有大写或小写s开头的行;至少有三种实现方式;

[root@qls ~]# grep "^[sS]" /proc/meminfo
[root@qls ~]# grep -i "^s" /proc/meminfo
[root@qls ~]# grep -E "^(s|S)" /proc/meminfo

#显示当前系统上root、CentOS或user1用户的相关信息;

[root@qls ~]# grep -E "^(root|CentOS|user1)" /etc/passwd

#找出/etc/init.d/functions文件中某单词后跟一个小括号的行;

[root@qls ~]# grep -E -o "^[_[:alnum:]]+\(\)" /etc/init.d/functions

#环境准备
[root@qls ~]# cat id.txt
邹 371481199403259478
莫 52020319810613433X
韩 46010619911113727A
荣 53012419750413543
荣 530124197504135438
阮 360702197902169951
任 6212231987082X5176
姜 370602198507189574
赵 BBB602198507189574

#找出正确的身份证号码

[root@qls ~]# egrep "[0-9]{17}[0-9X]" id.txt

正则表达式之SED文本处理

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
    Sed是一个流编辑器, 非交互式的编辑器,它一次处理一行内容. 处理时,把当前处理的行存储在临时缓冲区中,称
"模式空间"(pattern space)
接着用Sed命令处理缓冲区中的内容,处理完成后,把缓冲区的内容送往屏幕。接
着处理下一行,这样不断重复,直到文件末尾。文件内容并没有改变,除非你使用重定向存储输出。Sed是用来自动编辑一个或多个文件;简化对文件的反复操作;编写转换程序等。

01. Sed命令格式


sed [options] 'command' file(s)

Sed正则使用

与Grep一样,Sed在文件中查找模式时也可以使用正则表达式(RE)和各种元字符。正则表达式是括在斜杠间的模式,用于查找和替换,以下是sed支持的元字符。使用基本元字符集 ^, $, ., *, [], [^], < >, (), {} 使用扩展元字符集 ?, +, { }, |, ( ) 使用扩展元字符的方式 + sed -r

02. Sed命令示例


Sed对指定行进行操作,包括打印、删除、修改、追加等。

Sed选项参数

-e #允许多项编辑

-n #取消默认的输出

-i #直接修改对应文件

-r #支持扩展元字符

Sed命令参数

a #在当前行后添加一行或多行

c #在当前行进行替换修改

d #在当前行进行删除操作
i #在当前行之前插入文本
p #打印匹配的行或指定行

n #读入下一输入行,从下一条命令进行处理

! #对所选行以外的所有行应用命令

h #把模式空间里的内容重定向到暂存缓冲区

H #把模式空间里的内容追加到暂存缓冲区

g #取出暂存缓冲区的内容,将其复制到模式空间,覆盖该处原有内容

G #取出暂存缓冲区的内容,将其复制到模式空间,追加在原有内容后面

正则表达式之AWK文本处理

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
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
01. Awk基本介绍

什么是Awk?


awk是一种编程语言,用于在`linux/unix`下对文本和数据进行处理。
awk数据可以来自标准输入、一个或多个文件,或其它命令的输出。
awk通常是配合脚本进行使用, 是一个强大的文本处理工具。

awk 的处理文本和数据的方式如下:

1.进行逐行扫描文件, 从第一行到最后一行
2.寻找匹配的特定模式的行,在行上进行操作
3.如果没有指定处理动作,则把匹配的行显示到标准输出
4.如果没有指定模式,则所有被操作的行都被处理

Awk工作原理


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

1.awk将文件中的每一行作为输入, 并将每一行赋给内部变量 $0 , 以换行符结束

2.awk开始进行字段分解,每个字段存储在已编号的变量中,从$1开始[默认空格分割]
3.awk默认字段分隔符是由内部FS变量来确定, 可以使用-F修订

4.awk行处理时使用了print数打印分割后的字段

5.awk在打印后的字段加上空格,因为$1,$3之间有一个逗号。逗号被映射至OFS内部变量中,称为输出字段分隔符,OFS 默认为空格.
6.awk输出之后,将从文件中获取另一行,并将其存储在$0中,覆盖原来的内容,然后将新的字符串分隔成字段并进行处理。该过程将持续到所有行处理完毕.

Awk命令格式


#示例1, 匹配 awk 'pattern' filename

[root@qls ~]# awk '/root/' /etc/passwd

#示例2, 处理动作 awk '{action}' filename

[root@qls ~]# awk -F: '{print $1}' /etc/passwd

#示例3, 匹配+处理动作 awk 'pattern {action}' filename

[root@qls ~]# awk -F ':' '/root/ {print $1,$3}' /etc/passwd
[root@qls ~]# awk 'BEGIN{FS=":"} /root/{print $1,$3}' /etc/passwd

#示例4, 判断大于多少则输出什么内容 command |awk 'pattern {action}'

[root@qls ~]# df |awk '/\/$/ {if ($3>50000) print $4}'

06. Awk循环语句


while循环

[root@qls ~]# awk 'BEGIN{ i=1; while(i<=10){print i; i++} }'
[root@qls ~]# awk -F: '{i=1; while(i<=NF){print i; i++}}' /etc/passwd
[root@qls ~]# awk -F: '{i=1; while(i<=10) {print $0; i++}}' /etc/passwd
[root@qls ~]# cat b.txt
111 222
333 444 555
666 777 888 999
[root@qls ~]# awk '{i=1; while(i<=NF){print $i; i++}}' b.txt

for循环

#C 风格 for

[root@qls ~]# awk 'BEGIN{for(i=1;i<=5;i++){print i} }'

#将每行打印 10 次

[root@qls ~]# awk -F: '{ for(i=1;i<=10;i++) {print $0} }' passwd


Awk数组概述

将需要统计的某个字段作为数组的索引,然后对索引进行遍历

1 统计/etc/passwd 中各种类型 shell 的数量


[root@qls ~]# awk -F: '{shells[$NF]++} END{ for(i in shells){print i,shells[i]} }' /etc/passwd

2 网站访问状态统计<当前时实状态ss>


[root@qls ~]# ss -an|awk '/:80/{tcp[$2]++} END {for(i in tcp){print i,tcp[i]}}'

3 统计当前的tcp的11种状态数量<当前时实状态 netstat,ss>


[root@qls ~]# ss -ant|sed '1d'|awk '{status[$1]++} END {for(i in status){print i,status[i]}}'


Awk数组案例

Nginx日志分析,日志格式如下:

log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';

52.55.21.59 - - [22/Nova/2018:14:55:36 +0800] "GET /feed/ HTTP/1.1" 404 162 "https:#www.google.com/" "Opera/9.80 (Macintosh; Intel Mac OS X 10.6.8; U; de) Presto/2.9.168 Version/11.52" "-"
1 统计2018年11月22日,当天的PV量


[root@qls ~]# grep "22/Nov/2018" access.log |wc -l
[root@qls ~]# awk "/22\/Nov\/2018/" access.log |wc -l
[root@qls ~]# awk '/22\/Nov\/2018/ {ips[$1]++} END {for(i in ips) {sum+=ips[i]} {print sum}}' access.log

#统计11-12点的pv量

[root@qls ~]# awk '$4>="[22/Nov/2018:11:00:00" && $4<="[22/Nov/2018:12:00:00 {print $0}"' access.log |wc -l

2 统计2018年11月22日,一天内访问最多的10个IP


[root@qls ~]# awk '/22\/Nov\/2018/ {ips[$1]++} END {for(i in ips){ print ips[i],i}}' access.log |sort -rn|head

#统计11-12点访问次数最多的10个IP

[root@qls ~]# awk '$4>="[22/Nov/2018:15:00:00" && $4<="[22/Nov/2018:19:00:00"' access.log |awk '{ips[$1]++} END {for(i in ips){print ips[i],i}}'|sort -rn|head
3 统计2018年11月22日,访问大于100次的IP


[root@qls ~]# awk '/22\/Nov\/2018/ {ips[$1]++} END {for(i in ips){if(ips[i]>100){print i,ips[i]}}}' access.log

4 统计2018年11月22日,访问最多的10个页面($request top 10)


[root@qls ~]# awk '/22\/Nov\/2018/ {request[$7]++} END {for(i in request){print request[i],i}}' access.log |sort -rn|head

5 统计2018年11月22日,每个URL访问内容总大小($bodybytessent)


[root@qls ~]# awk '/22\/Nov\/2018/{size[$7]+=$10} END {for(i in size){print size[i],i}}' access.log |sort -rn|head

6 统计2018年11月22日,每个IP访问状态码数量($status)


[root@qls ~]# awk '{ip_code[$1 " " $9]++} END {for(i in ip_code){print ip_code[i],i}}' access.log|sort -rn|head

7 统计2018年11月22日,访问状态码为404及出现的次数($status)


[root@qls ~]# grep "404" access.log |wc -l
[root@qls ~]# awk '{if($9=="404") code[$9]++} END {for(i in code){print i,code[i]}}' access.log
8 统计2018年11月22日,8:30-9:00访问状态码是404


[root@qls ~]# awk '$4>="[22/Nov/2018:15:00:00" && $4<="[22/Nov/2018:19:00:00" && $9=="404" {code[$9]++} END {for(i in code){print i,code[i]}}' access.log
[root@qls ~]# awk '$9=="404" {code[$9]++} END {for(i in code){print i,code[i]}}' access.log

9 统计2018年11月22日,各种状态码数量


[root@qls ~]# awk '{code[$9]++} END {for(i in code){print i,code[i]}}' access.log

10 统计日志中所有URL访问的次数及访问响应的内容总大小


[root@qls ~]# awk '{request[$7]++;size[$7]+=$10} END {for(i in request){print request[i],i,size[i]}}' access.log |sort -rn|head