一、正则表达式
1.正则表达式概述
正则表达式REGEXP(Regular Expressions)由一类特殊字符及文本字符所编写的模式,其中有些字符(元字符)不表示字符字面意义,而表示控制或通配的功能,类似于增强版的通配符功能,但与通配符不同,通配符功能是用来处理文件名,而正则表达式是处理文本内容中字符。
正则表达式被很多程序和开发语言所广泛支持:vim,less,grep,sed,awk,nginx,mysql等。
正则表达式组成:
- 普通字符
大小写字母、数字、标点符号及一些其他符号 - 元字符
在正则表达式中具有特殊意义的专用字符
正则表达式的分类:
- 基础正则表达式
- 扩展正则表达式
- 编程语言支持的高级正则表达式
BRE和ERE语法基本一致,只有部分元字符(预定义的带有特殊含义的一些符号)需要区别对待。
扩展正则中这些元字符可直接使用:?、+、{、}、|、(、)。
基础正则中这些元字符前需要加反斜杠转义:?、+、{、}、|、(、\)。
点击查看代码
grep 、 sed 默认使用基础正则表达式
grep -E、sed -r、egrep、awk 扩展正则表达式
2.基础正则 元字符(字符匹配)
元字符 | 含义 |
---|---|
. | 匹配任意单个字符,可以是一个汉字(. 在[ ]中仅代表.)默认情况下 . 无法匹配换行符 |
[] | 匹配指定范围内的任意单个字符 [a-zA-Z0-9] |
[^] | 匹配指定范围外的任意单个字符 (取反 ) |
[4-59] | 代表匹配4、5、9 这三个字符中的任意单个字符,而不是4~59范围内的字符 |
\n | 匹配换行符 |
\t | 匹配制表符 |
点击查看代码
[root@node1 ~]# grep r..t /etc/passwd //.表示任意单个字符
root:x:0:0:root:/root:/bin/bash
operator:x:11:0:operator:/root:/sbin/nologin
ftp:x:14:50:FTP User:/var/ftp:/sbin/nologin
[root@node1 ~]# ls /etc/|grep rc[.0-6] //.在[]中仅仅代表点.这个字符
rc0.d
rc1.d
rc2.d
rc3.d
rc4.d
rc5.d
rc6.d
rc.d
rc.local
3.基础正则 表示次数(量词)
在基础正则表达式中,对于量词的元字符需要加上反斜线\进行转义。(扩展正则不用加\)量词写在字符串的后面,代表该字符串出现的次数
元字符 | 含义 |
---|---|
* | 匹配前面的字符任意次,包括0次 |
.* | 任意长度的任意字符 不包括0次 |
? | 匹配其前面的字符出现0次或1次 |
+ | 匹配其前面的字符出现至少1次 |
匹配前面的字符至少m次,至多n次 | |
匹配前面的字符至少n次 | |
匹配前面的字符至多n次,<=n |
点击查看代码
[root@node1 ~]# echo goooooogle |grep 'go*gle' //*表示0到+∞次
goooooogle
[root@node1 ~]# echo gdadadadgle |grep "g.*gle" //.*代表任意匹配所有
gdadadadgle
[root@node1 ~]# echo ggle |grep "go\?gle" //\?表示0次或1次
ggle
[root@node1 ~]# echo gogle |grep "go\?gle"
gogle
[root@node1 ~]# echo gooooogle |grep "go\?gle"
//未显示结果
[root@node1 ~]# echo gooooogle |grep "go\+gle" //\+表示1个及以上
gooooogle
[root@node1 ~]# echo gooooogle |grep 'go\{2,5\}gle' //代表前面的o出现2次以上5次以下
gooooogle
基础正则和扩展正则都支持贪婪匹配,不支持非贪婪匹配。如果想要在基础正则或扩展正则上实现非贪婪匹配,比较复杂,但也能实现。
4.位置锚点
符号 | 含义 |
---|---|
^ | 行首锚定, 用于模式的最左侧 |
$ | 行尾锚定,用于模式的最右侧 |
^$ | 空行 |
< | 匹配单词开头处的位置 |
> | 匹配单词结尾处的位置 |
\b | 匹配单词边界处的位置(开头和结尾), \bword\b 等价于 |
点击查看代码
[root@node1 ~]# cat /etc/fstab
#
# /etc/fstab
# Created by anaconda on Thu May 9 20:58:23 2024
#
# Accessible filesystems, by reference, are maintained under '/dev/disk'
# See man pages fstab(5), findfs(8), mount(8) and/or blkid(8) for more info
#
/dev/mapper/centos-root / xfs defaults 0 0
UUID=d13887da-6764-43a1-b6a8-f6d3dbf5ae4f /boot xfs defaults 0 0
/dev/mapper/centos-swap swap swap defaults 0 0
[root@node1 ~]# grep "^[^#]" /etc/fstab //过滤不是以#开头的非空行
/dev/mapper/centos-root / xfs defaults 0 0
UUID=d13887da-6764-43a1-b6a8-f6d3dbf5ae4f /boot xfs defaults 0 0
/dev/mapper/centos-swap swap swap defaults 0 0
[root@node1 ~]# echo hello-123 |grep "\<123" //除了字母、数字、下划线,其他都算单词的分隔符
hello-123
[root@node1 ~]# echo hello 123 |grep "\<123"
hello 123
5.分组与后向引用
分组:用()将多个字符捆绑在一起,当作一个整体处理。
使用小括号包围一部分正则表达式(pattern),这部分正则表达式即成为一个分组整体,也即成为一个子表达式。
- 小括号有两个隐含的功能
分组
自动捕获:保存分组的匹配结果,以后可以去引用这个捕获的结果
根据左括号的位置决定第几个分组。例如:(abc)def、([a-d]){3}、(([0-9])abc(def){2})(hgi)。
分组后可以使用\N来反向引用对应的分组的匹配结果,N是1-9的正整数,\1表示第一个分组表达式的匹配结构,\2表示第二个分组表达式的匹配结果,以此类推。
后向引用:
点击查看代码
示例:
[root@node1 ~]# echo abc123XYZ | sed -nr 's/(abc)(123)(XYZ)/\3\2\1/p'
XYZ123abc
//(abc)对应\1 (123)对应\2 (XYZ)对应\3
注意:只有扩展正则表达式(-r)才可以使用后向引用
二、文本三剑客只grep
命令格式:grep [选项] ... 匹配式/表达式 [文件名]或标准输入
选项 | 含义 |
---|---|
-m | 匹配到#行停止 (grep -m 1 root /etc/passwd //多个匹配只取第一行 ) |
-v | 反向匹配 ,输出与查找条件相反的行-i忽略字符大小写-n显示匹配的行号 |
-c | 统计匹配的行数 |
-o | 仅显示匹配到的字符串 |
-q | 静默模式,不输出任何信息(写脚本会用) |
-A | after, 后#行 (grep -A3 root /etc/passwd //匹配到的行的后3行也显示出来) |
-B | before, 前#行-Ccontext, 前后各#行 |
-e | 实现多个选项间的逻辑or或关系 (grep -e root -e bash /etc/passwd //包含root或者包含bash 的行) |
-w | 匹配整个单词 (grep -w root /etc/passwd ) |
-E | 使用扩展正则表达式 |
-f | 以文件作为匹配的条件 (过滤两个文件中重合的部分) |
-r | 递归目录,但不处理软链接 |
点击查看代码
面试题:
统计当前主机的连接状态
[root@localhost ~]# ss -nta | grep -v '^State' |cut -d" " -f1|sort |uniq -c
3 ESTAB
17 LISTEN
统计当前连接主机数
[root@node1 ~]# ss -nt |tr -s " "|cut -d " " -f5|cut -d ":" -f1 |sort|uniq -c
2 192.168.204.1
1 Address
三、文本三剑客只sed
sed是行编辑器
1.sed原理
Sed是从文件或管道中读取一行,处理一行,输出一行;再读取一行,再处理一行,再输出一行,直到最后一行。每当处理一行时,把当前处理的行存储在临时缓冲区中,称为模式空间(PatternSpace),接着用sed命令处理缓冲区中的内容,处理完成后,把缓冲区的内容送往屏幕。接着处理下一行,这样不断重复,直到文件末尾。
一次处理一行的设计模式使得sed性能很高,sed在读取大文件时不会出现卡顿的现象。如果使用vi命令打开几十M上百M的文件,明显会出现有卡顿的现象,这是因为vi命令打开文件是一次性将文件加载到内存,然后再打开。Sed就避免了这种情况,一行一行的处理,打开速度非常快,执行速度也很快
2.sed基本原理
sed 选项 '语法(地址+脚本命令)' 文本名/标准输入
常用选项:
选项 | 含义 |
---|---|
-n | 不输出模式空间内容到屏幕,即不自动打印 |
-e | 多点编辑 (sed -n -e '/^r/p' -e'/^b/p' /etc/passwd) |
-f | FILE从指定文件中读取编辑脚本 |
-r 或 -E | 使用扩展正则表达式 |
-i | 直接修改目标文本文件 |
-i.bak | 备份文件并原处编辑 |
点击查看代码
[root@node1 ~]# sed ' ' //默认将输入内容打印出来,系统自带自动打印
[root@node1 ~]# sed ' ' /etc/fstab //查看文件内容
[root@node1 ~]# sed ' ' </etc/fstab //支持重定向
[root@node1 ~]# cat /etc/issue |sed ' ' //支持管道符
3.sed脚本格式
'地址+命令'单引号中间需要写脚本,脚本格式如下:
点击查看代码
`地址`
1. 不给地址:对全文进行处理(比如行号)
2. 单地址:
#:指定的行
$:最后一行
/pattern/:被此处模式所能够匹配到的每一行,正则表达式
3. 地址范围:
#,# #从#行到第#行,3,6 从第3行到第6行
#,+# #从#行到+#行, 3,+4 表示从3行到第7行
/pat1/,/pat2/ 第一个正则表达式 到 第二个正则表达式之间的行 //后3种不推荐
#,/pat/ 从#号行为开始找到 pat为止
/pat/,# 找到#号个pat为止
4. 步进:~
1~2 奇数行
2~2 偶数行
点击查看代码
`命令`
p 打印当前模式空间内容,追加到默认输出之后
Ip 忽略大小写输出
d 删除模式空间匹配的行,并立即启用下一轮循环
a [\]text 在指定行后面追加文本,支持使用\n实现多行追加
i [\]text 在行前面插入文本
c [\]text 替换行为单行或多行文本
w file 保存模式匹配的行至指定文件 seq 10 |sed -n '2wa.txt'
r file 读取指定文件的文本至模式空间中匹配到的行后 seq 10|sed '2r /etc/issue'
= 为模式空间中的行打印行号 sed '2=' /etc/passwd sed -n -e '=;p' /etc/passwd
! 模式空间中匹配行取反处理 seq 10 |sed -n '1~2!p'
q 结束或退出sed seq 10 | sed '3q'
4.搜索代替
格式:'s///'
点击查看代码
行范围 s/旧字符串/新字符串/替换标记
#4种替换标记:
数字:表明新字符串将替换第几处匹配的地方
g:表面新字符串将会替换所有匹配的地方
p:打印与替换命令匹配的行,与-n一起使用
w 文件:将替换的结果写入文件中
点击查看代码
s /旧字符(可用正则)/新字符(不可用正则!)/
[root@node1 ~]# sed -n '/r..t/p' /etc/passwd //匹配以r开头以t结尾,中间2个任意字符
root:x:0:0:root:/root:/bin/bash
operator:x:11:0:operator:/root:/sbin/nologin
ftp:x:14:50:FTP User:/var/ftp:/sbin/nologin
想要给匹配到的内容后面都加上er怎么做?
sed -n ‘s/r..t/&er/p’ /etc/passwd //&指代前面匹配到的内容!!!
5.变量
sed可以识别bash环境里的变量
点击查看代码
[root@node1 ~]# name=root //自定义变量
[root@node1 ~]# sed -nr '/$name/p' /etc/passwd //此处使用单引号不显示结果
[root@node1 ~]# sed -nr "/$name/p" /etc/passwd //使用双引号,变量直接引用
root:x:0:0:root:/root:/bin/bash
operator:x:11:0:operator:/root:/sbin/nologin
[root@node1 ~]# sed -nr '/'$name'/p' /etc/passwd //变量处使用单引号把变量括起来
root:x:0:0:root:/root:/bin/bash
operator:x:11:0:operator:/root:/sbin/nologin
sed可以调用变量来改文件
点击查看代码
[root@node1 ~]# port=8080 //可以使用变量来修改端口号
[root@node1 ~]# sed -ri 's/^Listen 80/Listen '$port'/' httpd.conf
6.sed的高级用法
sed中除了模式空间,还支持保持空间(Hold Space),利用此空间,可以将模式空间中的数据,临时保存至保存空间,从而后续接着处理,实现更为强大的功能。
点击查看代码
`常见的高级命令`
P 打印模式空间开端至\n内容,并追加到默认输出之前
h 把模式空间中的内容覆盖至保持空间中
H 把模式空间中的内容追加至保持空间中
g 从保持空间取出数据覆盖至模式空间
G 从保持空间取出内容追加至模式空间
x 把模式空间中的内容与保持空间中的内容进行互换
n 读取匹配到的行的下一行覆盖至模式空间
N 读取匹配到的行的下一行追加至模式空间
d 删除模式空间中的行
D 如果模式空间包含换行符,则删除直到第一个换行符的模式空间中的文本,并不会读取新的输入行,而使
用合成的模式空间重新启动循环。如果模式空间不包含换行符,则会像发出d命令那样启动正常的新循环
示例:打印偶数行
点击查看代码
seq 10 | sed -n 'n;p' //高级用法
seq 10 | sed -n '2~2p'
seq 10 | sed '1~2d'
seq 10 | sed -n '1~2!p'
四、文本三剑客之awk
awk是列处理器
1.awk概述
awk的工作原理
- 逐行读取文本,默认以空格或tab键为分隔进行分隔,将分隔所得的各个字段保存到内建变量中,并按模式或者条件执行编辑命令。
- awk倾向于将一行分成多个“字段”然后再进行处理。
- awk信息的读入也是逐行读取的,执行结果可以通过print的功能将字段数据打印显示。
- 使用awk命令的过程中,可以使用逻辑操作符“&&”表示与、“|”表示或、“!”表示非,还可以进行简单的数学运算,如+、-、*、/、%、^分别表示加、减、乘、除、取余和乘方。
awk的命令格式:
点击查看代码
awk [选项] 'program' [文件名]
`常见选项:`
-F分隔符 :指明输入时用到的字段分隔符,默认的分隔符是若干个连续空白符
-v :var=value 变量赋值
'program'格式:
pattern{action statements;..}
表达式 + 处理动作
pattern:决定动作语句何时触发及触发事件,比如:BEGIN,END,正则表达式等
action statements:对数据进行处理,放在{}内指明,常见:print
基本用法
点击查看代码
[root@node1 ~]# awk '{print "hello"}' //字符串需要添加双引号
1
hello
2
hello
`示例:打印分区利用率`
[root@node1 ~]# df
文件系统 1K-块 已用 可用 已用% 挂载点
/dev/mapper/centos-root 10475520 5201356 5274164 50% /
devtmpfs 917604 0 917604 0% /dev
tmpfs 933524 0 933524 0% /dev/shm
tmpfs 933524 9280 924244 1% /run
tmpfs 933524 0 933524 0% /sys/fs/cgroup
/dev/sda1 1038336 182376 855960 18% /boot
tmpfs 186708 44 186664 1% /run/user/0
/dev/sr0 4414592 4414592 0 100% /run/media/root/CentOS 7 x86_64
[root@node1 ~]# df | awk '{print $5}' |awk -F% '{print $1}' //先打印第五列,再以%为分隔符打印第一列
已用
50
0
0
1
0
18
1
100
[root@node1 ~]# df | awk -F"[ %]+" '{print $5}' //以空格和%为分隔符,+代表一个及以上,打印第五列
已用
50
0
0
1
0
18
1
100
3.内置变量
内置变量是awk预定义好的、内置在awk内部的变量
注意-v选项
|内置变量|含义|
|FS|表示每行文本的字段分隔符,默认是空格或制表符Tab|
|NF(number of Field)|表示字段数量变量,在处理记录时,它表示当前记录的字段数|
|NR|表示记录的数量变量,在处理文件时,它表示当前处理的是第几行|
|FNR|显示多个文件的行号|
|$0|表示整个输入记录|
|$n|当前处理行的第n个字段(第n列)|
|OFS|输出时的分隔符,默认是空格|
|RS|行分隔符,默认是换行符,预设值是\n|
|FILENAME|被处理的文件名|
3.FS输入分隔符
点击查看代码
[root@node1 ~]# awk -v FS=':' '{print $1FS$3}' /etc/passwd |head //-v 变量赋值,以:为分隔符,打印第一列和第三列
root:0
bin:1
daemon:2
adm:3
lp:4
sync:5
shutdown:6
halt:7
mail:8
operator:11
点击查看代码
`传参:`
[root@node1 ~]# fs=:
[root@node1 ~]# echo $fs
:
[root@node1 ~]# awk -v FS=$fs '{print $1}' /etc/passwd |head //定义变量传给FS
root
bin
daemon
adm
lp
sync
shutdown
halt
mail
operator
OFS输出分隔符
点击查看代码
[root@node1 ~]# awk -F: '{print $1,$3}' /etc/passwd |head -n5 //默认输出分隔符为空格
root 0
bin 1
daemon 2
adm 3
lp 4
[root@node1 ~]# awk -F: -v OFS='==' '{print $1,$3}' /etc/passwd |head -n5 //OFS指定输出分隔符为==
root==0
bin==1
daemon==2
adm==3
lp==4
[root@node1 ~]# awk -F: '{print $1"=="$3}' /etc/passwd |head -n5
root==0
bin==1
daemon==2
adm==3
lp==4
RS行分隔符
点击查看代码
[root@node1 ~]# echo $PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin
[root@node1 ~]# echo $PATH | awk -v RS=':' '{print $0}' //指定:为行分隔符
/usr/local/sbin
/usr/local/bin
/usr/sbin
/usr/bin
/root/bin
NF(number of Fieid)
点击查看代码
[root@node1 ~]# df | awk '{print NF}' //NF代表字段的个数
6
6
6
6
6
6
6
6
8
[root@node1 ~]# df | awk '{print $NF}' //$NF等于$6,打印第六列
挂载点
/
/dev
/dev/shm
/run
/sys/fs/cgroup
/boot
/run/user/0
x86_64
[root@node1 ~]# df | awk '{print $(NF-1)}' //打印第五列
已用%
50%
0%
0%
1%
0%
18%
1%
7
NR
点击查看代码
[root@node1 ~]# awk '{print NR}' /etc/fstab //NR表示每一行的行号
1
2
3
4
5
6
7
8
9
10
11
[root@node1 ~]# awk 'NR==2{print $1}' /etc/passwd //NR==2代表第二行记录
bin:x:1:1:bin:/bin:/sbin/nologin
[root@node1 ~]# awk -F: 'NR==2{print $1}' /etc/passwd //以:为分隔符,打印第二行的第一列
bin
[root@node1 ~]# awk -F: 'NR==2{print NR,$1}' /etc/passwd //print后面加NR可以显示行号
2 bin
[root@node1 ~]# awk -F: 'NR==2{print $0}' /etc/passwd //$0表示当前处理的行的整行内容
bin:x:1:1:bin:/bin:/sbin/nologin
[root@node1 ~]# awk -F: 'NR>=3 && NR<=5{print NR,$0}' /etc/passwd //取大于等于3小于且等于5的行
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
# &&代表且,||代表或
[root@node1 ~]# awk -F: 'NR%2==0{print NR,$0}' /etc/fstab //打印出函数取余数为0的行,即偶数行
2 #
4 # Created by anaconda on Thu May 9 20:58:23 2024
6 # Accessible filesystems, by reference, are maintained under '/dev/disk'
8 #
10 UUID=d13887da-6764-43a1-b6a8-f6d3dbf5ae4f /boot xfs defaults 0 0
[root@node1 ~]# awk -F: 'NR%2==1{print NR,$0}' /etc/fstab //打印出函数取余数为1的行,即奇数行
1
3 # /etc/fstab
5 #
7 # See man pages fstab(5), findfs(8), mount(8) and/or blkid(8) for more info
9 /dev/mapper/centos-root / xfs defaults 0 0
11 /dev/mapper/centos-swap swap swap defaults 0 0
[root@node1 ~]# awk -F: '$1 ~ /root/{print NR,$0}' /etc/passwd //打印第一列中含有root的行
1 root:x:0:0:root:/root:/bin/bash
4.awk自定义变量
awk -v 自定义变量 'program'[文件名]
5.模式PATTERN
1.模式为空
如果模式为空表示每一行都匹配成功,相当于没有额外条件
点击查看代码
例: awk -F: '{print $1,$3}' /etc/passwd
2.正则匹配
/regular expression/:仅处理能够模式匹配到的行,需要用//括起来
点击查看代码
例:
[root@node1 ~]# awk '/^UUID/{print $1}' /etc/fstab //打印第一列以UUID开头的行
UUID=d13887da-6764-43a1-b6a8-f6d3dbf5ae4f
3.line ranges 行范围
不支持使用行号,但是可以使用变量NR间接指定行号加上比较操作符或者逻辑关系
点击查看代码
`算术操作符`
x+y, x-y, x*y, x/y, x^y, x%y
-x:转换为负数
+x:将字符串转换为数值
`比较操作符`
==, !=, >, >=, <, <=
`逻辑`
与:&&,并且关系
或:||,或者关系
非:!,取反
`模式匹配符`
~ 左边是否和右边匹配,包含关系
!~ 是否不匹配
4.BEGIN、END
- BEGIN{ }:仅在开始处理文件中的文本之前执行一下
- END{ }:仅在文本处理完成之后执行一次
点击查看代码
awk 'BEGIN{...};{...};END{...}' 文件
#处理过程:
1、在awk处理指定的文本之前,需要先执行BEGIN{...}模式里的命令操作;
2、中间的{...} 是真正用于处理文件的命令操作;
3、在awk处理完文件后才会执行END{...}模式里的命令操作。END{ }语句块中,往往会放入打印结果等语句。
6.关系表达式
关系表达式结构为 真 才会被处理
真:结果为非0值,非空字符串
假:结果为空字符串或0值
点击查看代码
[root@node1 ~]# seq 3 |awk '1' //1为真,打印
1
2
3
[root@node1 ~]# seq 3 |awk '0' //0为假,不打印
[root@node1 ~]# seq 3 |awk 'n++' //除了第一行,都打印
2
3
[root@node1 ~]# seq 3 |awk '!n++' //只打印第一行
1
[root@node1 ~]# seq 10 |awk 'i=!i' //打印奇数行
1
3
5
7
9
[root@node1 ~]# seq 10 |awk '!(i=!i)' //打印偶数行
[root@node1 ~]# seq 10 |awk -v i=1 'i=!i' //打印偶数行
2
4
6
8
10