当前位置:首页 > Liunx > 正文内容

shell中正则表达式-05

邓鹏10个月前 (01-13)Liunx183

课程目标

  • 掌握常用的正则表达式元字符含义

  • 掌握sed的删除行操作

  • 掌握sed的打印行操作

  • 掌握sed的增加行操作

  • 掌握sed的修改替换操作


正则表达式

正则表达式介绍

正则表达式(Regular Expression、regex或regexp,缩写为RE),也译为正规表示法、常规表示法,是一种字符模式,用于在查找过程中匹配指定的字符。

几乎所有开发语言都支持正则表达式,后面学习的python语言里也有正则表达式.

linux里主要支持正则表达式的命令有grep, sed, awk

正则一

表达式说明示例
[]括号里的字符任选其一[abc][0-9][a-z]
[^]不匹配括号里的任意字符(括号里面的^号为"非",不是开头)[^abc]表示不是a,不是b,不是c
^[]以括号里的任意单个字符开头(这里的^是开头的意思)^[abc]:以a或b或c开头
^[^]不以括号里的任意单个字符开头
^行的开头^root
$行的结尾bash$
^$空行

示例: 准备一个文件

# vim 1.txt
boot
boat
rat
rot
root
Root
brot.
查找有rat或rot字符的行
# grep r[oa]t 1.txt      
rat
rot
brot.
查看非r字符开头,但2-4个字符为oot的行
# grep ^[^r]oot 1.txt
boot
Root
查找有非大写字母与一个o字符连接的行
# grep '[^A-Z]o' 1.txt
boot
boat
rot
root    
Root   # 这个也可以查出来,因为第2-3个字符符合要求
brot.
查找不以r和b开头的行
# grep ^[^rb] 1.txt
Root
查找以rot开头以rot结尾的行(也就是这一行只有rot三个字符)
# grep ^rot$ 1.txt
rot


查找.号结尾的字符,需要转义并引号引起来(比较特殊,因为下面就要讲到.号是特殊的元字符)
# grep "\."$  1.txt
brot.

问题: 使用grep输出/etc/vsftpd/vsftpd.conf配置文件里的配置(去掉注释与空行)

提示: grep -v取反
别忘了grep -E扩展模式可以实现或
如: grep -E "root|ftp" /etc/passwd

# yum install vsftpd -y


# grep -v ^# /etc/vsftpd/vsftpd.conf |grep -v ^$
# grep -v '^#|^$' /etc/vsftpd/vsftpd.conf

问题: 使用grep输出/etc/samba/smb.conf配置文件里的配置(去掉注释与空行)

# yum install samba -y

# grep -v -E '#|^;|^$' /etc/samba/smb.conf |grep [a-z]
注:
samba配置文件是个比较奇葩的配置文件,在不同版本格式都有所不同,所以不同版本会有不同的答案。请灵活对待


grep加上关键字颜色显示(centos7默认就有颜色)

在/etc/bashrc最后的空白处追加一句
# vim /etc/bashrc
alias grep='grep --color=auto'

# source /etc/bashrc


正则二

表达式功能
[[:alnum:]]大小写字母与数字
[[:alpha:]]字母字符(包括大小写字母)
[[:blank:]]空格与制表符
[[:digit:]]或[0-9]          (==常用==)数字
[[:lower:]]或[a-z]        (==常用==)小写字母
[[:upper:]]或[A-Z]       (==常用==)大写字母
[[:punct:]]标点符号
[[:space:]]包括换行符,回车等在内的所有空白

查找不以大写字母开头的行
# grep '^[^[:upper:]]' 1.txt    # 这个取反的写法很特殊,^符在两个中括号中间(了解即可)
# grep  '^[^A-Z]' 1.txt 
# grep -v '^[A-Z]' 1.txt
查找有数字的行
# grep '[0-9]' 1.txt
# grep [[:digit:]] 1.txt
查找一个数字和一个字母连起来的行
# grep -E '[0-9][a-Z]|[a-Z][0-9]' grep.txt    # grep -E是扩展模式,中间|符号代表"或者"


问题: 请问汉语描述grep [^a-z] 1.txt是查找什么?

查找不全部是小写字母的行

示例: 输入一个字符,判断输入的是大写字母还是小写字母还是数字,还是其它

方法一:
#!/bin/bash

read -n 1 -p "input a char:" char   # -n 1代表输入1个字符后就自动回车了
echo          # echo代表换行

case "$char" in       # 使用case语句对$char进程多分支判断
 [[:upper:]] )      # 正则表达式匹配大写字母,(注意:这里用[A-Z]匹配不了)
  echo "大写字母"
  ;;
 [[:lower:]] )      # 正则表达式匹配小写字母,(注意:这里用[a-z]匹配不了)
  echo "小写字母"
  ;;
 [[:digit:]] )      # 正则表达式匹配数字
  echo "数字"
  ;;
 * )
  echo "其它"
esac


方法二:
#!/bin/bash

read -n 1 -p "input a char:" char   # -n 1代表输入1个字符后就自动回车了
echo          # echo代表换行

# 使用if多分支进行判断
if [[ $char =~ [A-Z] ]];then   # [[ ]]两个中括号里写判断条件,里面使用=~匹配正则表达式
 echo "大写字母"
elif [[ $char =~ [a-z] ]];then
 echo "小写字母"
elif [[ $char =~ [0-9] ]];then
 echo "数字"
else
 echo "其它"
fi

练习: read -s输入一个密码, 判断此密码复杂度.(长度大于等于8位,并且有大小写字母和数字三类字符)




正则三

名词解释:

元字符: 指那些在正则表达式中具有特殊意义的专用字符, 如:点(.) 星(*) 问号(?)等

前导字符:即位于元字符前面的字符 ab==c==*   aoo==o==.

==注意:== 元字符如果想表达字符本身需要转义,如.号就想匹配"."号本身则需要使用\.

字符字符说明示例
*前导字符出现0次或者连续多次ab*  abbbb
.除了换行符以外,任意单个字符ab.   ab8 abu
.*任意长度的字符ab.*  abdfdfdf
{n}前导字符连续出现n次             (需要配合grep -E或egrep使用)[0-9]{3}
{n,}前导字符至少出现n次             (需要配合grep -E或egrep使用)[a-z]{4,}
{n,m}前导字符连续出现n到m次      (需要配合grep -E或egrep使用)o{2,4}
+前导字符出现1次或者多次    (需要配合grep -E或egrep使用)[0-9]+
?前导字符出现0次或者1次      (需要配合grep -E或egrep使用)go?
( )组字符

示例文本:

# vim 2.txt
ggle
gogle
google
gooogle
gagle
gaagle
gaaagle
abcgef
abcdef
goagle
aagoog
wrqsg

问题:一起来看看下面能查出哪些字符,通过结果理解记忆

# grep g.  2.txt
# grep g*  2.txt      # 结果比较怪
# grep g.g 2.txt
# grep g*g 2.txt
# grep go.g 2.txt
# grep go*g 2.txt
# grep go.*g 2.txt
# grep -E go{2}g 2.txt
# grep -E 'go{1,2}g' 2.txt  # 需要引号引起来,单引双引都可以
# grep -E 'go{1,}g' 2.txt  # 需要引号引起来,单引双引都可以
# grep -E go+g 2.txt
# grep -E go?g 2.txt


示例: 查出eth0网卡的IP,广播地址,子网掩码

image.png

1555429788701

# ifconfig eth0 | grep -E -o '([0-9]{1,3}\.){3}[0-9]{1,3}'
10.1.1.11
10.1.1.255
255.255.255.0
解析:
[0-9]{1,3}\.      代表3个数字接一个.号
([0-9]{1,3}\.){3}  前面用小括号做成一个组,后面{3}代表重重复3次
[0-9]{1,3}     最后一个数字后不需要.号


示例: 匹配邮箱地址

# echo "daniel@126.com" | grep -E '^[0-9a-zA-Z]+@[a-z0-9]+\.[a-z]+$'
解析:
^[0-9a-zA-Z]+@       代表@符号前面有1个或多个字符开头(大小写字母或数字)
@[a-z0-9]+\.[a-z]+$   代表@符号和.号(注意.号要转义)中间有1个或多个字符(小写字母或数字)
      .号后面有1个或多个字符(小写字母)结尾


perl内置正则(拓展)

Perl内置正则(需要使用grep -P来匹配),这种匹配方式在python也有。但不建议都记住,上面所学的就完全够用了.

\d      匹配数字  [0-9]
\w      匹配字母数字下划线[a-zA-Z0-9_]
\s      匹配空格、制表符、换页符[\t\r\n]


sed

sed介绍

# man sed
sed  - stream editor for filtering and trans-forming text

Windows下的编辑器:

1555508121170image.png

linux下的编辑器:

  • ==vi或vim==1

  • gedit

  • emacs等

image.png

  • 首先sed把当前正在处理的行保存在一个临时缓存区中(也称为模式空间),然后处理临时缓冲区中的行,完成后把该行发送到屏幕上。

  • sed把每一行都存在临时缓冲区中,对这个副本进行编辑,所以不会修改原文件。当然你也可以选择修改源文件,需要sed -i 操作的文件

学习sed的关键是要搞清楚,它是一个流==编辑器==,编辑器常见的功能有:

  • 删除行

  • 打印行

  • 增加行

  • 替换(修改)

sed参数
-e 进行多项编辑,即对输入行应用多条sed命令时使用
-n 取消默认的输出
-r  使用扩展正则表达式
-i inplace,原地编辑(修改源文件)

sed操作
d  删除行
p  打印行
a  后面加行
i  前面加行
s  替换修改

删除行操作

==d(delete)代表删除==

使用数字匹配行

指定删除第2行

# head  -5 /etc/passwd |cat -n |sed  2d

变量引用需要双引号
a=2     
# head -5 /etc/passwd |cat -n |sed "$a"d

删除第2行到第3行,中间的逗号表示范围

# head -5 /etc/passwd |cat -n |sed  2,3d

删除第1行和第5行,中间为分号,表示单独的操作

错误,需要引号引起来
# head -5 /etc/passwd |cat -n |sed 1d;5d
正确
# head -5 /etc/passwd |cat -n |sed '1d;5d'

删除第1,2,4行, -e参数是把不同的多种操作可以衔接起来

head -5 /etc/passwd |cat -n |sed -e '2d;4d' -e '1d'


问题:下面操作代表什么

# head -n 5 /etc/passwd |cat -n |sed  '1d;3d;5d'

# head -n 5 /etc/passwd |cat -n |sed  '1,3d;5d'

使用正则匹配行

如果不知道行号,但知道行里的某个单词或相关字符,我们可以使用正则表达式进行匹配

删除匹配oo的行

# head -n 5 /etc/passwd |cat -n |sed  '/oo/d'

删除以root开头的行

# head -n 5 /etc/passwd |sed '/^root/d'

删除以bash结尾的行

# head -n 5 /etc/passwd |sed '/bash$/d'

其它任意正则表达式都可以匹配

练习:(注意: -i参数会直接操作源文件,所以请先不加-i测试,测试OK后再加-i参数)

sed -i删除/etc/vsftpd/vsftpd.conf里所有的注释和空行

# sed -i '/^#/d;/^$/d' /etc/vsftpd/vsftpd.conf

sed -i删除/etc/samba/smb.conf里所有的注释和空行

# sed -i '/#/d;/;/d;/^$/d;/^\t$/d' /etc/samba/smb.conf

打印行操作

打印行(删除的反义)

==p(print)代表打印==

使用数字匹配行

打印第1行

# head  -5 /etc/passwd |cat -n | sed  1p
     1  root:x:0:0:root:/root:/bin/bash    # 会在原来5行的基础上再打印第1行
     1  root:x:0:0:root:/root:/bin/bash
     2  bin:x:1:1:bin:/bin:/sbin/nologin
     3  daemon:x:2:2:daemon:/sbin:/sbin/nologin
     4  adm:x:3:4:adm:/var/adm:/sbin/nologin
     5  lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin

# head  -5 /etc/passwd |cat -n | sed -n 1p   # 正确做法加一个-n参数
     1  root:x:0:0:root:/root:/bin/bash

打印第1行和第4行

# head  -5 /etc/passwd |sed -ne '1p;4p'

打印1-4行

# head  -5 /etc/passwd |sed -ne '1,4p'

使用正则匹配行

打印有root关键字的行

# head -5 /etc/passwd |sed -n '/root/p'

打印以root开头的行

# head -5 /etc/passwd |sed -n '/^root/p'

找出var/log/secure日志里成功登录的ssh信息

方法1:
# sed -n '/Accepted/p' /var/log/secure
方法2:
# grep Accepted /var/log/secure
方法3:(awk还没学,先了解一下)
# awk '$0~"Accepted" {print $0}' /var/log/secure


增加行操作

==a(append)代表后面加行==

==i(insert)代表前面插入行==

准备一个文件

# cat 1.txt
11111
22222
44444
55555

在第2行后加上33333这一行

# sed -i '2a33333' 1.txt
# cat 1.txt
11111
22222
33333
44444
55555

在第1行插入00000这一行

# sed -i '1i00000' 1.txt
# cat 1.txt
00000
11111
22222
33333
44444
55555

也可以用正则匹配行,这里表示在4开头的行的后一行加上ccccc这一行

# sed -i '/^4/accccc' 1.txt 

# cat 1.txt
00000
11111
22222
33333
44444
ccccc
55555

修改替换操作

sed的修改替换格式与vi里的修改替换格式一样

使用数字匹配行

替换每行里的第1个匹配字符

# head  -5 /etc/passwd |sed 's/:/===/'
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

全替换

# head  -5 /etc/passwd |sed 's/:/===/g'
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

替换2-4行

# head  -5 /etc/passwd |sed '2,4s/:/===/g'
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

替换2行和4行

# head  -5 /etc/passwd |sed '2s/:/===/g;4s/:/===/g'
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

替换第2行的第1个和第3个匹配字符

注意后面的数字是2,前面替换了1个,剩下的里面替换第2个也就是原来的第3个
# head  -5 /etc/passwd |sed '2s/:/===/;2s/:/===/2'
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

使用正则匹配行

替换以daemon开头的那一行

# head -5 /etc/passwd |sed '/^daemon/s/:/===/g'
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


&符号在sed替换里代表前面被替换的字符

理解下面两句的不同:
s/[0-9]/ &/
s/[0-9]/ [0-9]/


练习: 使用脚本实现修改主机名(假设改为a.b.com)

# hostname a.b.com
# sed -i '/HOSTNAME=/s/server.cluster.com/a.b.com/' /etc/sysconfig/network
# echo "10.1.1.11 a.b.com" >> /etc/hosts

练习: 修改/etc/selinx/config配置文件,将selinux关闭

# sed -i '/SELINUX=/s/enforcing/disabled/' /etc/selinux/config

sed分域操作(拓展)

将()之间的字符串(==一般为正则表达式==)定义为组,并且将匹配这个表达式的保存到一个区域(一个正则表达式最多可以保存9个),它们使用\1到\9来表示。然后进行替换操作

注意: sed分域操作的格式就是替换修改.

示例: 把hello,world.sed变成world,sed.hello(注意: 1个逗号1个点号)

方法1:
# echo "hello,world.sed" | sed 's/\(.*\),\(.*\)\.\(.*\)/\2,\3.\1/'
world,sed.hello
此方法\符太多了,建议使用-r扩展模式,就不用加\转义括号了

方法2:
# echo "hello,world.sed" | sed -r 's/(.*),(.*)\.(.*)/\2,\3.\1/'
world,sed.hello

方法3:
# echo "hello,world.sed" | sed -r 's/(.....)(.)(.....)(.)(...)/\3\2\5\4\1/'
world,sed.hello

方法4:
# echo "hello,world.sed" | sed -r 's/(.{5})(.)(.{5})(.)(.{3})/\3\2\5\4\1/'
world,sed.hello


示例: 以/etc/passwd文件前5行为例,进行如下处理

删除每行的第一个字符

# head -5 /etc/passwd |cut -c2-
# head -5 /etc/passwd |sed -r 's/(.)(.*)/\2/'
# head -5 /etc/passwd |sed -r 's/.//1'
# head -5 /etc/passwd |sed -r 's/^.//'

删除每行的第九个字符

# head -5 /etc/passwd |cut -c1-8,10-
# head -5 /etc/passwd |sed -r 's/(.{8})(.)(.*)/\1\3/'
# head -5 /etc/passwd |sed -r 's/.//9'

删除倒数第5个字符

# head -5 /etc/passwd |rev |cut -c1-4,6- |rev
# head -5 /etc/passwd |sed -r 's/(.*)(.)(....)/\1\3/'

把每行的第5个字符和第8个字符互换,并删除第10个字符

# head -5 /etc/passwd | sed -r 's/(....)(.)(..)(.)(.)(.)(.*)/\1\4\3\2\5\7/'


课后练习

写一个简单初始化系统的脚本

1, 修改主机名(也就是说你获取IP为10.1.1.11,则主机名改成server11.cluster.com)

2, 配置可以使用的本地yum

3, 关闭防火墙与selinux

4, 安装配置vsftpd,不允许匿名用户登录,配置完后启动服务并设置为开机自动启动

5, 可在此基础上继续自由发挥扩展



扫描二维码推送至手机访问

版权声明:本文由PowerShell中文社区发布,如需转载请注明出处。

本文链接:https://www.powershell.com.cn/?id=32

分享给朋友:

“shell中正则表达式-05” 的相关文章

Shell脚本介绍

Shell脚本介绍

今日目标了解Shell脚本概念磁盘相关命令回顾:磁盘相关命令说明fdisk分msdos分区与要看系统硬盘与分区情况lsblk查看块设备与其挂载情况df -h查看已经挂载的文件系统情况mount也是查看挂载的情况,还能看到挂载的参数(ro或rw等)iostat需要安装sysstat软件包,动态查看磁盘...

Liunx定时计划任务配置说明

Liunx定时计划任务配置说明

在 Linux 中,* 代表通配符,用于表示任意值。在 cron 任务中,* 可以用来指定分钟、小时、日期等时间单位的取值。具体而言,cron 表达式由五个时间字段组成,分别表示分钟(0-59)、小时(0-23)、日期(1-31)、月份(1-12)和星期几(0-7,其中0和7都表示星期日)。这些时间...

CentOS7 服务器上使用T4显卡部署大型AI模型的详细教程

CentOS7 服务器上使用T4显卡部署大型AI模型的详细教程

环境准备服务器配置CPU:Platinum8225c 显卡T4 GPU:T4 16GB  CPU:8核 内存32GB操作系统:Centos7.6英伟达显卡驱动Docker容器环境Docker使用的NVIDIA驱动Ollama容器镜像,Ollama支持的显卡型号:点击查看查看运行环境的资源使...

发表评论

访客

◎欢迎参与讨论,请在这里发表您的看法和观点。