1. 正则概述
1.什么是正则表达式
以特定的符号表示一组数字或字母的,一种规则。
原始数据 --->> 正则表达式 --->> 过滤后的数据
|
过滤掉的数据
**
2.为什么要使用正则表达式
再工作中,我们时刻面对着大量的日志,程序,以及命令的输出。迫切的需要过滤我们需要的一部分内容,甚至是一个字符串。比如现在有一个上千行的文件,我们仅需要其中包含root”的行,怎么办?此时就需要使用到正则表达式的规则来筛选想要的内容。
3.正则表达式注意事项
1.正则表达式应用非常广泛,存在于各种编程语言中。
2.正则表达式 和 Linux的通配符以及特殊字符是有区别的。
3.要想学好 grep、 sed,ak首先就需要对正则表达式有一定的了解。只有了解了规则,才能灵活的运用。
[root@web01 shell-grep]# egrep "[0-9]{12}" test.txt
not 572891888887.
[root@web01 shell-grep]# egrep "[8]{5}" test.txt
not 572891888887.
[root@web01 shell-grep]# egrep "[8]{2,5}" test.txt
my qq num is 572891887.
not 572891888887.
2. 正则demo示例、实际场景一些需求
2.1 grep
需求1:使用grep正则方式方式,提取eth0的IP地址。
数字 10.0.0.1
#10 172 192 至少出现2次,最多3次
#至少出现1次,最多出现3次
[root@web01 shell-grep]# ifconfig eth0 | egrep -o "[0-9]{2,3}.[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}"|head -1
10.0.0.7
[root@web01 shell-grep]# ifconfig eth0 | egrep -o "[[:digit:]]{2,3}.[[:digit:]]{1,3}.[[:digit:]]{1,3}.[[:digit:]]{1,3}"|head -1
10.0.0.7
需求2:使用grep正则表达式方式,排除nginx配置文件的空行和#号开头的行。
[root@web01 shell-grep]# egrep -v "^# | [[:space:]]+# | ^$" /etc/nginx/nginx.conf
需求3:使用grep正则表达式方式,匹配nginx日志中的http1.0 和http1.1 http2.1 http2.0\统计一下他们出现的次数。
1 1.0 1.1
2 2.0 2.1
[root@web01 shell-grep]# egrep -o "HTTP/(1|2).(1|0)" access.log_58 | sort |uniq -c
1650 HTTP/1.0
165294 HTTP/1.1
1 HTTP/2.0
需求4:使用grep正则表达式方式,匹配zabbix_agentd.conf配置文件中所有已启用的配置。
[root@web01 shell-grep]# egrep "^[a-Z]" /etc/zabbix/zabbix_agentd.conf
PidFile=/var/run/zabbix/zabbix_agentd.pid LogFile=/var/log/zabbix/zabbix_agentd.log LogFileSize=0 Server=127.0.0.1 ServerActive=127.0.0.1 Hostname=web01 Include=/etc/zabbix/zabbix_agentd.d/*.conf
需求5:使用grep正则表达式方式,匹配133、152、166、135开头的手机号码。(写成一个脚本)
1.手机号:必须是11位
2.开头占了3为,后面只需要8位即可
[root@web01 shell-grep]# egrep “(133|152|166|135)[0-9]{8}” phone.txt
[root@web01 shell-grep]# cat phone.sh
#!/bin/bash
##############################################################
File Name: phone.sh
Author: oldxu
Organization: 552408925@qq.com
##############################################################
read -p "请输入你的手机号,系统会给你发送短信: " Action
#1.判断用户输入的必须是全整数
if [[ "$Action" =~ [2]+$ ]];then
#2.判断用户输入的手机号是否满足133|152|166|135 必须是11位
if [[ $Action =~ ^(133|152|166|135)[0-9]{8}$ ]];then
echo "你输入的 $Action 手机号系统判定合法"
else
#3.如果手机号出现了问题,则看是否大于11位、或是小于11、如果都不是则直接提示该手机号位在系统备案
if [ ${#Action} -gt 11 ];then
echo "你输入的手机号超过了11位,请输入正确手机号"
elif [ ${#Action} -lt 11 ];then
echo "你输入的手机号低于11位,请输入正确手机号"
else
echo "你输入的 $Action 手机号未在该系统备案"
fi
fi
else
echo "你输入的手机号有误。"
exit
fi
需求6:使用grep正则表达式方式,匹配 qq、163、sina的 email地址。
egrep “^([0-9]|[a-z]|[A-Z])+@(qq|sina|163).com” mail.txt
33.Shell-grep-sed.html
[root@web01 shell-grep]# cat mail.sh
#!/bin/bash
##############################################################
File Name: mail.sh
Author: oldxu
Organization: 552408925@qq.com
##############################################################
read -p "请输入你要验证的email [ qq | 163 | sina ]: " Action
if [[ $Action =~ ^([0-9]|_|[a-z]|[A-Z])+@(qq|sina|163).com$ ]];then
echo " $Action 验证成功"
else
echo "$Action 验证失败"
fi
需求7:取出身份证,匹配是哪个省,什么时间出生的,是男还是女,是它们省第几个出生的。
身份证位数: 18
最后一位x: 0
年龄: 从第7位开始到12位
倒数第二位: 奇数为男 偶数为女
最后四位: 代表是本省第多少个出生。
使用 grep正则表达式⽅式,匹配 a b c 三类IP地址。
10.0.0.0 ~ 10.255.255.255 a 172.16.1.0 ~172.16.31.254 b 192.168.1.0 ~ 192.168.255.255 c
_
[root@web01 shell-case]# cat test.sh
#!/bin/bash
思路:
- 0-254: ([0-9]|[1-9][0-9]|[1][0-9][0-9]|[2][0-5][0-5]) # 0-9 10-99 100-199 200-255 覆盖全
- 1-31: ([1-9]|[1-2][0-9] |([3][0-1])) #同理
read -p "请输⼊需要校验的IP地址: " Action
if [[ $Action =~ ^(10)\.([0-9]|[1-9][0-9]|[1][0-9][0-9]|[2][0-4][0-9]|[2][5]
[0-5])\.([0-9]|[1-9][0-9]|[1][0-9][0-9]|[2][0-4][0-9]|[2][5][0-5])\.([0-9]|[1-
9][0-9]|[1][0-9][0-9]|[2][0-4][0-9]|[2][5][0-5])$ ]];then
echo " $Action 属于A类地址"
elif [[ $Action =~ ^(172)\.([1][6-9]|[2][0-9]|[3][0-1])\.([0]|[1][0-9]
{0,2}|[2][0-9]|[2][0-4][0-9]|[2][0-5][0-5]|[3-9][0-9])\.([0]|[1][0-9]{0,2}|[2]
[0-9]|[2][0-4][0-9]|[2][0-5][0-5]|[3-9][0-9])$ ]];then
echo "$Action 属于B类地址"
elif [[ $Action =~ ^(192)\.(168)\.([0]|[1][0-9]{0,2}|[2][0-9]|[2][0-4][0-9]|
[2][0-5][0-5]|[3-9][0-9])\.([0]|[1][0-9]{0,2}|[2][0-9]|[2][0-4][0-9]|[2][0-5]
[0-5]|[3-9][0-9])$ ]];then
echo "$Action 属于C类地址"
else
echo "$Action 不属于地址"
fi
2.2 sed
2.2.1 sed基本概述
1.sed(Stream Editor),流编辑器。
能够对标准输出或文件进行逐行处理。
简单来说,sed可以实现对文件的增、删、查、改。
2.sed工作模式sed读取文件一行,存放在缓存区,然后处理,最后输出。
3.sed基础语法第一种形式: stdout |sed [option] “pattern command”第二种形式: sed [option] “pattern command” file
2.2.2 sed用法概述:
sed
选项:
-i 直接变更文件内容
-n 取消打印该文件内容
-e 进行多个条件的编辑
-f 指定一个文件,读取该文件中的sed表达式
-r 支持扩展正则表达式
pattrn:
相当于根据条件过滤文件内容 。
sed也有grep的功能,变更文件内容
command:
p:打印
d:删除 结合-i选项
i:在匹配的行前追加内容,或者是在文件的多少行前直接添加
a:在匹配的行后追加内容,或者是在文件的多少行后直接添加
c:可以通过正则的方式直接替换文件中的内容
sg: s/old/new/g 替换 s###g s@@@g
2.1 sed-option 选项
sed [option] file
选项 | 含义 |
---|---|
-n | 只打印匹配的行(取消文件的默认输出) |
-e | 允许多项编辑 |
-f | 编辑动作保存在文件,指定文件才执行 |
-r | 支持扩展正则表达式 |
-i | 直接变更文件内容 |
#-n
[root@web01 shell-sed]# sed -n '/shell/p' test.txt
I love shell
#-n-e
[root@web01 shell-sed]# sed -n -e '/shell/p' -e '/SHELL/p' test.txt
I love shell
I love SHELL
#-f
[root@web01 shell-sed]# cat t.sed
/shell/p
[root@web01 shell-sed]# sed -n -f t.sed test.txt
I love shell
#-r
[root@web01 shell-sed]# sed -n -r '/shell|SHELL/p' test.txt
I love shell
I love SHELL
#-i
[root@web01 shell-sed]# sed -i 's/shell/Linux/g' test.txt
[root@web01 shell-sed]# cat test.txt
I love Linux
I love SHELL
This is test file
演示:
cp /etc/passwd ./
sed -n '10p' passwd
sed -n '10,20p' passwd
sed -n '1,+5p' passwd
sed -n '/^root/p' passwd
sed '/bin/,/ftp/p' passwd
sed '/bin/,/mail/p' passwd
sed -n '/bin/,/mail/p' passwd
sed -n '1,/^mail/p' passwd
2.2 sed-pattern 匹配
sed [option] ‘/pattern/cmd’ file
1)打印/etc/passwd中第20行
sed -n '20p' passwd
2)打印/etc/passwd中从第8行开始,到第15行结束的内容
sed -n '8,15p' passwd
3)打印/etc/passwd中从第8行开始,然后+5行结束的内容
sed -n '8,+5p' passwd
4)打印/etc/passwd中开头匹配bin字符串的内容
sed -n '/^bin/p' passwd
5)打印/etc/passwd中开头为root的行开始,到开头为ftp的行结束的内容
sed -n '/root/,/ftp/p' passwd
6)打印/etc/passwd中第8行开始,到含有/sbin/nologin的内容的行结束内容
sed -n '8,//sbin/nologin/p' passwd
2.3 sed-command 命令
2.3.1 sed追加命令
a (append) | 行后插入追加内容 |
---|---|
i (insert) | 行前插入追加内容 |
r (read) | 读入外部文件,行后插入 |
w (write) | 将匹配写入外部文件 |
示例:
1 ) passwd文件第10行后面追加“Add Line”
sed -i '10a "Add Line"' passwd
2)passwd文件第10行到第20行,没一行后面都追加 "Test Line"
sed -i '10,20a "Test Line"' passwd
3)passwd文件匹配到/bin/bash的行后面追加 "Insert Line"
sed -i '//bin/bash/a "Insert Line"' passwd
4)passwd文件匹配到以bin开头的行,在匹配的行前住家 "Add Line Before"
sed -i '/^bin/i "Add Line Before"' passwd
5)passwd文件每一行前面都追加 “Insert Line Before”
sed -i 'i "Insert Line Before"' passwd
6)将/etc/fstab文件的内容追加到passwd文件的第10行后面
sed -i '10r /etc/fstab' passwd
7)将/etc/inittab文件内容追加到passwd文件匹配/bin/sync行的后面
8)将/etc/hosts文件内容追加到passwd文件中10行的后面
9)将passwd文件匹配到/bin/bash的行追加到/tmp/sed.txt文件中
sed -n '//bin/bash/p' >> /tmp/sed.txt
10)将passwd文件丛第10行开始,到匹配到nfsnobody开头的所有行内容追加到/tmp/sed-1.txt
sed -n '10,/^nfsnobody/p' >> /tmp/sed-1.txt
2.3.1 sed 删除命令
sed -i ‘ d’ file 示例:
1)删除/etc/passwd中的第15行
sed -i '15d' passwd
2)删除/etc/passwd中的第8行到第14行的所有内容
sed -i '8,14d' passwd #或者 sed -i '8,+7d' passwd
3)删除/etc/passwd中以/sbin/nologin结尾的行
sed -i '//sbin/nologin$/d' passwd
4)删除/etc/passwd中以bin开头的行,到以ntp开头的行的所有内容
sed -i '/bin/,/ntp/d' passwd
5)删除/etc/passwd中第3行到以ftp开头的所有行内容
sed -i '3,/^ftp/d' passwd
6)典型需求:删除Nginx配置文件中所有的注释以及空行
sed -ri '/#|$/d' /etc/nginx/nginx.conf
2.3.2 sed 修改 | 替换
c:替换行
s: 替换 g: global全局
示例
1s/old/new/ | 替换第1行内容old为new |
---|---|
1,10s/old/new/ | 替换1行到10行的内容old为new |
1,+5s/old/new/ | 替换1行到6行的内容old为new |
/pattern1/s/old/new/ | 替换匹配patternl的内容old为new |
/pattern1/,/pattern2/s/old/new/ | 替换匹配到pattern1的行直到匹配到pattern2的所有行内容old为new10, |
10/patternl/s/ old/new/ | 替换第10行直到匹配到pattern1的所有行内容old为new |
‘/^127.0.0.1/ s/$/ test/‘ /etc/hosts | 在文件尾部添加内容($符替换为添加内容) |
练习
sed '/^SeLINUX=/c SeLinux=minimum' passwd
sed -ri '/^SeLINUX=/c SeLinux=minimum' /etc/selinux/config
sed -ri '/^SELINUX=/c SeLinux=disabled' /etc/selinux/config
sed -ri '/^SELINUX=.*/c SELINUX=disabled' /etc/selinux/config
sed 's/^/#/' /etc/nginx/nginx.conf #sed -i 's/^/#/' /etc/nginx/nginx.conf
sed练习、脚本
需求:处理一个MySQL配置文件的my.cnf文件。
1.输文件中有几个段,一对 [ ] 为一段。
2.针对每个段统计配置文件参数总个数。
[root@oldxu ~]# sh example.sh
1: client 2
2: server 12
3: mysqld 12
4: mysqld_safe 7
5: embedded 8
6: mysqld-5.5 10
[root@web01 shell-sed]# cat sed.sh
my.conf.txt
#!/bin/bash
#思路:
#1.打印每段的内容 sed -n '/[.*/p' my.cnf | sed -e 's#[##g' -e 's#]##g'
#2.统计每段内容的总参数次数 sed -n '/[server]/,/[.*/p' my.cnf |egrep -v "#|[|^$" | wc -l
#提取每个段的名称
name=$(sed -n '/[.*/p' my.cnf | sed -e 's#[##g' -e 's#]##g')
#提取每个段的参数总数,但需要传递该段的名称才能获取到他的总数
mysql_num () {
sed -n '/['$1']/,/[.*/p' my.cnf |egrep -v "#|[|^$" | wc -l
}
index=0
for item in ${name}
do
index=$[ $index +1 ]
echo "$index: $item : $(mysql_num $item)"
done
需求: 处理一个ansible的invtory主机清单。
-1.输出主机组,一对 [ ] 为一个主机组。
-2.输出每个主机组下的主机总个数。
[root@oldxu ~]# sh example.sh
-1: web01: 有 2 台主机
-2: web02: 有 12 台主机
扩展需求:
[root@web01 shell-sed]# sh sed_ansible.sh
编号: 1 主机组名称: web 有 5 台主机 , 主机分别是 172.16.1.1 172.16.1.2 172.16.1.3 172.16.1.4 172.16.1.5
编号: 2 主机组名称: db 有 4 台主机 , 主机分别是 172.16.1.8 172.16.1.9 172.16.1.10 172.16.1.11
编号: 3 主机组名称: nfs 有 2 台主机 , 主机分别是 172.16.1.31 172.16.1.32
编号: 4 主机组名称: db01 有 3 台主机 , 主机分别是 172.16.1.51 172.16.1.52 172.16.1.53
编号: 5 主机组名称: backup 有 3 台主机 , 主机分别是 172.16.1.41 172.16.1.42 172.16.1.43
#1.取出主机组名称 sed -n '/[/p' hosts | sed -r -e 's#[##g' -e 's#]##g'
#2.根据主机组名称在来统计下面的主机数量。 sed -n '/[db]/,/[/p' hosts |egrep -v "[.*]|^$" | wc -l
[root@web01 shell-sed]# cat sed_ansible.sh
#!/bin/bash
#############################################################
#1.取出主机名称:
Host_Name=$(sed -n '/[/p' hosts | sed -r -e 's#[##g' -e 's#]##g')
#2.通过传参方式将主机组名称传递进来,获取主机的总数。
Host_Total() {
sed -n '/['$1']/,/[/p' hosts |egrep -v "[.*]|^$" | wc -l
}
######################################################
number=0
for item in ${Host_Name}
do
number=$[ $number + 1 ]
echo "编号: $number 主机组名称: $item 有 $(Host_Total $item) 台主机"
done
[root@web01 shell-sed]# cat sed_ansible.sh
#!/bin/bash
##############################################################
#1.取出主机名称:
Host_Name=$(sed -n '/[/p' hosts | sed -r -e 's#[##g' -e 's#]##g')
#2.通过传参方式将主机组名称传递进来,获取主机的总数。
Host_Total() {
sed -n '/['$1']/,/[/p' hosts |egrep -v "[.*]|^$" | wc -l
}
Host_List () {
sed -n '/['$1']/,/[/p' hosts |egrep -v "[.*]|^$" | xargs
}
######################################################
number=0
for item in ${Host_Name}
do
number=$[ $number + 1 ]
echo "编号: $number 主机组名称: $item 有 $(Host_Total $item) 台主机 , 主机分别是 $(Host_List $item)"
done
[root@web01 shell-sed]# sh sed_ansible.sh
编号: 1 主机组名称: web 有 5 台主机 , 主机分别是 172.16.1.1 172.16.1.2 172.16.1.3 172.16.1.4 172.16.1.5
编号: 2 主机组名称: db 有 4 台主机 , 主机分别是 172.16.1.8 172.16.1.9 172.16.1.10 172.16.1.11
编号: 3 主机组名称: nfs 有 2 台主机 , 主机分别是 172.16.1.31 172.16.1.32
编号: 4 主机组名称: db01 有 3 台主机 , 主机分别是 172.16.1.51 172.16.1.52 172.16.1.53
编号: 5 主机组名称: backup 有 3 台主机 , 主机分别是 172.16.1.41 172.16.1.42 172.16.1.43
sed命令专项
2:在/tmp/file.txt文件中不以#开头的行的行首增加#号
[root@manager ~/sed]# sed -i 's/^[^#]/#&/g' file.txt
[root@manager ~/sed]# sed -i '/^[^#]/s/^/#/g' file.txt
3:用命令行更改/tmp/file.txt文件,把里面所有的“name”更改为“address”
[root@web01 shell-sed]# sed -i 's@name@address@g' file.txt
[root@manager ~/sed]# sed -i 's/^[^#]/#&/g' file.txt
4:利用sed命令将/tmp/file.txt中所有的回车替换成空格?
[root@web01 shell-sed]# cat file.txt | xargs
sed ':label;N;s/\n/ /;b label' file.txt
#oldboy #my qq num is 49000448.$ #not 4900000448. #my god ,i am not oldbey,but clsn!$ #oldboy #my address is oldboy.$ # not oldman. # my god ,i am not oldbey,but clsn!$ # i like linux
5:为/tmp/file.txt文件中前2行的行首加#号
[root@manager ~/sed]# sed '1,2 s/^[^#]/#&/g' file.txt
6:打印/tmp/file.txt文件中的第5行
[root@manager ~/sed]# sed -n '5p' file.txt
7:删除/tmp/file.txt文件中的带特殊字符的行
[root@web01 shell-sed]# sed -i '/[^0-9a-Z ]/d' file.txt
[[:alnum:]] 就是:[0-9A-Za-z]
8:删除#号及#后面的所有空白字符;
[root@web01 shell-sed]# sed -i '/#/d' file.txt
9:查找/tmp/file.txt文件中1到10行之间,同时将"qq"替换为"we","not"替换"no"
[root@manager ~/sed]# sed -n -i -e '1,10s/qq/we/p' -e '1,10s/not/no/p' file.txt
10:使用sed命令打印出file.txt文件的第一行到第三行
[root@manager ~/sed]# sed -n '1,3p' file.txt
11:删除文件/tmp/file.txt中所有带有数字的行
sed -i '/[0-9]/d' filei
12:删除/tmp/file.txt文件第3行到第10行的内容?
sed -i '3,10d' file
13:删除file.txt文件中的行首的空白字符。
[root@manager ~/sed]# sed -r -i -n 's/^[ ]+//gp' file.txt
[root@manager ~/sed]# sed -n '/^$/d' file.txt
14:使用sed将/tmp/file.txt文件中第2行的448替换成558
sed -i '2s#488#588#gp' file.txt
15:使用sed将/tmp/file.txt文件中所有$删除
sed 's#$##g' file.txt
16:将/tmp/file.txt中所有小写字母替换成大写字母
[root@web01 shell-sed]# sed -r 's#[a-z]#\U&#g' file.txt
17:将/tmp/file.txt文件中第2到第8行之间所有大写字母替换成小写字母
[root@manager ~/sed]# sed '2,8s#[A-Z]#\l&#g' file.txt
18:使用sed找出/tmp/file.txt文件中包含oldboy的行
[root@manager ~/sed]# sed '/oldboy/p' file.txt
19:将/tmp/file.txt文件中以;结尾的行,行首插入#
[root@manager ~/sed]# sed -n -i '/;/s/^/#/gp' file.txt
20:将/tmp/file.txt文件中第3和第5行的大写字母替换成小写字母
21:删除/tmp/file.txt文件中第2行到下一个以#号开头的行之间所有空行
[root@web01 shell-sed]# sed -n '2,/^#/p' file.txt | sed '/^$/d'
22:删除file.txt文件中的空行
[root@web01 shell-sed]# sed -i '/^$/d' file.txt
23:删除/tmp/file.txt文件中所有以#开头的行的行首的#
[root@web01 shell-sed]# sed -n '/^#/p' file.txt | sed 's####g'
24:使用sed将selinux彻底关闭
[root@web01 shell-sed]# sed '/SELINUX=/c SELINUX=disabled' /etc/selinux/config
25:修改passwd文件中第4行到第7行中所有的/sbin/nologin为/bin/bash
[root@web01 shell-sed]# sed -n '4,7s#/sbin/nologin#/bin/bash#gp' /etc/passwd
26:把/目录下所有以.txt结尾的文件中包含oldgirl的字符串全部替换为oldboy
sed -i 's#oldtest#old123#g' $(find ./ -type f -name "*.txt")
27:passwd文件的第2、8行前面都追加 "Insert Line Before" i
[root@manager ~/sed]# sed -e '2iInsert Line Before' -e '8iInsert Line Before' file.txt
28:将passwd文件的内容,添加到/tmp/file.txt文件中第3行的后面 r
29:使用sed命令打印出系统版本
[root@web01 shell-sed]# cat /etc/redhat-release | sed -r 's#(^. se) (.) ((.*)#\2#g'
7.5.1804
30 利用sed 取出ifconfig命令中本机的IPv4地址
[root@oldxu ~]# ifconfig eth0 | sed -rn '2s/^.*et //p' | sed -rn 's/ ne.*//p'
[root@oldxu ~]# ifconfig eth0 |sed -nr '2s/(^.*et) (.*) (net.*)/\2/p'
31 把data目录及其子目录下所有以扩展名.txt结尾的文件中包含oldgirl的字符串全部替换为oldboy.