正则表达式 grep

基础正则

        REGEXP: Regular Expressions,由一类特殊字符及文本字符所编写的模式,其中有些字符(元字符)不表示字符字面意义,而表示控制或通配的功能,类似于增强版的通配符功能,但与通配符不同,通配符功能是用来处理文件名,而正则表达式是处理文本内容中字符。

        正则表达式被很多程序和开发语言所广泛支持:vim, less,grep,sed,awk, nginx,mysql 等

正则表达式的主要作用是:匹配字符串(命令结果、文本内容)

通配符的作用是:匹配已存在文件名

正则表达式的分类:

  • 基础正则表达式(BRE:basic regular expression)
  • 扩展正则表达式(ERE:extended regular expression)
  • 编程语言支持的高级正则表达式

基础正则和扩展正则
语法基本一致,只有部分元字符(预定义好的带有特殊含义的一些符号)需要区别对待。

扩展正则
中这些元字符可直接使用:


+

{

}

|

(

)

基础正则
中这些元字符前需要加反斜线转义:
\?

\+

\{

\}

\|

\(

\)

grep sed
默认使用基础正则表达式

grep -E

sed -r

egrep

awk
扩展正则表达式

搜索字符的方式

1. 精确搜索

2.正则表达式搜索

  • 元字符:预定义好的具有特殊含义的符号,这些符号能够进行通配
  • 可读性非常的差
  • 写正则表达式不难

1.1元字符

  • abc 匹配字符串”abc”,普通字符的匹配
  • [abcde…] :匹配中括号内的任意单个字符

             a[xyz]b
:axb

ayb

azb
,不能匹配
aab amb

  • \n :匹配换行符
  • \t :匹配制表符
  • \w :匹配单词字符 [a-zA-Z0-9_]
  • \W :匹配非单词字符 [^a-zA-Z0-9_]
  • \s :匹配空白字符
  • \S :匹配非空白字符
  • \d :匹配数字
  • \D :匹配非数字
  • . 表示匹配任意单个字符

默认情况下
.  
无法匹配换行符,可在多行模式下设置匹配模式修饰符使之真正匹配任意字符,包括换行符

注意有些程序并不完全支持上面的反斜线转义元字符。例如
gnu grep 2.6
版本不支持
\s

\d
,而
gnu grep

2.20
支持
\s
但不支持
\d

sed
不支持
\d

上面所说的
单词
(word)
,在正则表达式中的含义:
[a-zA-Z0-9_]
组成的字符或字符串都是单词,例如
nihao,

hello world_
第一个单词是
nihao
,第二个单词是
hello
,第三个单词是
world_

元字符点(.)

示例:

[root@localhost ~]#ls /etc/|grep rc[.0-6]
#此处的点代表字符
rc0.d
rc1.d
rc2.d
rc3.d
rc4.d
rc5.d
rc6.d
rc.d
rc.local

[root@localhost ~]#ls /etc/|grep rc.
#此处的点代表任意单个字符
#rc. 表示过滤出含有rc后面任意单个字符的行
rc0.d
rc1.d
rc2.d
rc3.d
rc4.d
rc5.d
rc6.d
rc.d
rc.local


[root@localhost ~]#ls /etc/ | grep 'rc\.'
#点值表示点需要转义,要加引号
rc.d
rc.local



[root@localhost ~]# grep r..t /etc/passwd         
#r..t    ..代表任意两个字符
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@localhost ~]#cat 1.txt
abc
adc
a.c
asdc

[root@localhost ~]#grep a.c 1.txt
#表示原来的点需要加\转义
abc
adc
a.c
[root@localhost ~]#grep a\.c 1.txt
#不加引号有时匹配会有出入
abc
adc
a.c
[root@localhost ~]#grep 'a\.c' 1.txt
a.c
#标准格式需要加'' 或者""
[root@localhost ~]# ls |grep '[zhou].txt'    
#匹配[]中任意一个字符
h.txt
o.txt
u.txt
z.txt
[root@localhost ~]# ls [a-d].txt                
#通配符
a.txt  A.txt  b.txt  B.txt  c.txt  C.txt  d.txt
[root@localhost ~]# ls |grep '[a-d].txt'             
#真正的小写在正则表达式中
a.txt
b.txt
c.txt
d.txt
[root@localhost ~]# ls |grep '[^a-z].txt'   
#显示非小写字母
A.txt
B.txt

[root@localhost ~]# ls |grep '[^a.z].txt'     
#[]里就是本意不需要转义
#这段表示过滤出除了a.txt,..txt ,z.txt,其它都显示。
space空格
[root@localhost ky15]#grep [[:space:]] zhen.txt 
hhh  
jj		l
kkk  
[root@localhost ky15]#grep [[:space:]] zhen.txt |cat -A
hhh  $
jj^I^Il$
kkk  $

字符组

普通中括号包围的字符组:表示某单个字符匹配中括号内的任一字符即匹配成功

  • x[abc]z :可以匹配包含”xaz”、”xbz”、”xcz”的字符串
  • 取反表示法:中括号内开头使用 ^ ,表示只要不是中括号中的字符就匹配

         x[^abc]z
:可匹配包含
“xdz”

“xez”
等的字符串,但不能匹配包含
“xaz”

“xbz”

“xcz”
的字符串

  • 范围表示法:

        [a-z]
:代表任一单个小写字母

                [^a-z]
:只要单个非小写字母的其它任一单个字符

        [A-Z]
:代表任一单个大写字母

        [0-9]
:代表任一单个数字

                注:
[0-59]
表示匹配
0

1

2

3

4

5

9
而不是
0

59
中间的数值

        [a-z0-9A-Z]
:代表任一字母或数字

        [a-z0-9A-Z_]
:代表任一字母、数字或下划线,即匹配
单词字符

word

        [A-z]或
[a-Z]
:建议不要使用这种横跨大小写字母的范围表达式,不同地方表达的含义不同

        甚至有些按照字典顺序排序时,
[a-d]
不是等价于
abcd
,而是等价于
aBbCcDd
。如果想要等价于 abcd,应将
locale
环境设置为
C

LC_ALL=C

  • 特殊元字符在中括号中的匹配:

        想要在括号中匹配^,可以加上转义符或者在中括号中放在非开头位置,如[\^a],[a^]

字符类

将字符分成不同的类别,称为字符类
(character class)

下面是
POSIX
标准的字符类。

字符类 含义

[:lower:]

等价于
a-z

[:upper:]

等价于
A-Z

[:alpha:]

等价于
A-Za-z
,也等价于
[:lower:]
+
[:upper:]

[:digit:]

等价于
0-9

[:alnum:]

等价于
0-9A-Za-z
,也等价于
[:lower:]
+
[:upper:]
+
[:digit:]

[:xdigit:]

匹配十六进制数字
0 1 2 3 4 5 6 7 8 9 A B C D E F a b c d e f

[:blank:]

匹配空格或制表符

[:space:]

匹配空格、制表符、换行符、换页符、垂直制表符、回车符等等所有空白符号

[:punct:]

(Punctuation)
匹配所有标点符号,
! ” # $ % & ‘ ( ) * + , – . / : ; ?

@ [ \ ] ^ _ ` {

[:print:]

可打印字符,等价于
[:alnum:]
+
[:punct:]
+
空格

[:graph:]

图形字符,即能展现字符颜色的符号,等价于
[:alnum:]
+
[:punct:]

[:cntrl:]

所有的控制符号,八进制的
000

037,
以及
177 (
DEL
)

有些语言还额外提供一些非
POSIX
的字符类,比如
[:ascii:]
表示任一
ASCII
表中的字符。

使用字符类时,需使用中括号包围:

  • [[:alpha:]] :任一字母
  • [^[:alpha:]] :任一非字母
  • [^[:alpha:]0-3] :任一非字母且非0 1 2 3

等价类和排序类
(
了解
)

[=x=]
包围时表示
等价类

equivalence class
),等价类表示将普通字母和带有重音的字母分为一类。例如

aāá
ǎ
à
是一类,它等价于
[=a=]

oōó
ǒ
ò
又是一类,等价于
[=o=]
。注:没有
[=ao=]
这样连在一起的类。

例如:

echo “aāá
ǎ
à” | grep ‘[[=a=]]’

[.xyz.]
包围时表示
排序类
(collating symbol)
,排序类表示将
[..]
包围中的多个符号当作一个字符,但要

求在字符集中预先定义映射关系,例如已经预定义了
xyz
对应于
R
,那么
a[[.xyz.]]a
可以可以匹配
aRa

1.2 表示匹配次数

量词

* 匹配前面字符出现 0 到正无穷,包括0次,贪婪模式:尽可能长的匹配
.* 任意长度的任意字符  不包括0次     1到正无穷
\? 匹配其前面的字符出现0次或1次,即:可有可无
\+ 匹配其前面的字符出现最少1次,即:肯定有且 >=1 次      

到正无穷

\{n\} 匹配前面的字符n次
\{m,n\} 匹配前面的字符至少m次,至多n次
\{,n\} 匹配前面的字符至多n次,<=n
\{n,\} 匹配前面的字符至少n次

使用grep加-E 即可不用转义{}

举例:

[root@localhost ~]# echo google |grep 'go\{2\}gle'
#带表前面的o出现2次
google
[root@localhost ~]# echo gooooogle |grep 'go\{2,\}gle'  
#带表前面的o出现2次以上
gooooogle
[root@localhost ~]# echo gooooogle |grep 'go\{2,5\}gle'
#带表前面的o出现2次以上5次以下
gooooogle
[root@localhost ~]# echo goooooogle |grep 'go\{2,5\}gle'
[root@localhost ~]# 
[root@localhost ~]# echo goooooogle |grep 'go*gle'    
#表示0次到任意次
goooooogle
[root@localhost ~]# echo ggle |grep "go*gle"
ggle
[root@localhost ~]# echo gggle |grep "go*gle"    
#grep 包含最前面的g不匹配
gggle
[root@localhost ~]# echo gdadadadgle |grep "g.*gle"    
#.*代表任意匹配所有
gdadadadgle
[root@localhost ~]# echo ggle |grep "go\?gle"      
# \?一次或者0次
ggle
[root@localhost ~]# echo gogle |grep "go\?gle"
gogle
[root@[root@localhost ~]# echo google |grep "go\+gle"   
#一个以上
google
[root@localhost ~]# echo gogle |grep "go\+gle"
gogle
[root@localhost ~]# echo ggle |grep "go\+gle"
[root@localhost ~]# echo google |grep "go\?gle"


[root@localhost ~]#echo abc|grep   "[abc]\{3\}"
#需要加引号   
#他的  匹配思路是   [abc]\{3\}   在匹配abc的时候 
#第一轮 看  首字母  是否有abc中的一个,  第二轮也是看是否有abc中的一个  第三轮也是看是否有abc中的一个

实例:如何使用grep过滤出当前主机的IP地址

方法一、
ifconfig ens33|grep netmask|grep -o '[0-9]\+\.[0-9]\+\.[0-9]\+\.[0-9]\+'|head -n1

扩展正则
ifconfig ens33|grep netmask|grep -Eo '[0-9]+.[0-9]+.[0-9]+.[0-9]+'|head -n1

方法二、
ifconfig ens33|grep netmask|grep -o '[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}'|head -n1

ifconfig ens33|grep netmask|grep -Eo '[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}'|head -n1

1.3 位置匹配(锚定)

^ 行首锚定, 用于模式的最左侧        表示开头
$ 行尾锚定,用于模式的最右侧        表示结尾
^字符$ 匹配只有 此字符 的 行(^root$  匹配只有root的行)
^$ 空行
^[[:space:]]*$ 空白行
\<   或   \b 词首锚定,用于单词模式的左侧(连续的数字,字母,下划线都算单词内部)
\>   或   \b 词尾锚定,用于单词模式的右侧
\ 匹配整个单词

例子:

思考过滤出不是已#号开头的非空行
[root@localhost ~]#grep "^[^#]" /etc/fstab


[root@localhost data]#cat test.txt 
google
googler
ggoogle
ggler
[root@localhost data]#grep '^google$' test.txt 
google
#只匹配google 这个字符


匹配空白行
[root@localhost data]#grep "^[[:space:]]*$" /etc/fstab

[root@localhost data]#



[root@localhost ~]#echo hello-123 |grep "\<123"
#除了 字母 数字 下划线其他都算 单词的分隔符
hello-123
[root@localhost ~]#echo hello 123 |grep "\<123"
hello 123

1.4 分组或其它

分组:(   ) 将多个字符捆绑在一起,当作一个整体处理,如:\(root\)+

后向引用:分组括号中的模式匹配到的内容会被正则表达式引擎记录于内部的变量中,这些变量的命名

反向引用对应的分组的匹配结果

方式为: \1, \2, \3, …      分组   (\ 为转义符)

\1 表示第一个分组表达式的匹配结果

\2 表示第二个分组表达式的匹配结果

根据左括号的位置决定第几个分组。

例如: (abc)def 、 ([a-d] ){3} 、 (([0-9])abc(def){2})(hgi)

注意:反向引用所引用的是分组匹配后的结果,不是分组表达式。

正则表达式
(abc|def) and \1xyz
可以匹配字符串
“abc and abcxyz”

“def and defxyz”
,但是不能匹


“abc and defxyz”

“def and abcxyz”

[root@localhost data]#echo "abc and abcxyz" | grep -E "(abc|def) and \1xyz"
abc and abcxyz

[root@localhost data]#echo "abc and defxyz" | grep -E "(abc|def) and \1xyz"
[root@localhost data]#
#把abcxyz改为defxyz后就无法匹配了。

方法一、
[root@localhost data]#echo "abc and defxyz" | grep -E "(abc|def) and (abc|def)xyz"
abc and defxyz

方法二、
[root@localhost data]#echo "abc and defxyz" | grep -P '(abc|def) and \1xyz'
#无法匹配

[root@localhost data]#echo "abc and defxyz" | grep -P '(abc|def) and (?1)xyz'
abc and defxyz

或者:二选一表达式

\|    (\表示转义符)

示例:

[root@localhost ~]#echo abccc |grep -E "abc{3}"  #c出现三次
abccc


[root@localhost ~]#echo abcabcabc |grep -E "(abc){3}"
#分组 匹配abc  把abc当作一个整体
abcabcabc


[root@localhost ~]#echo 1abc |grep -E "1|2abc"
#只匹配了1
1abc
#这段的意思是匹配 1 或 2abc


[root@localhost ~]#echo 1abc |grep -E "(1|2)abc"
#1abc或者2abc
1abc


-E 是扩展正则 ,不用在()|前面加上转义符


实例:如何使用grep过滤出当前主机的IP地址

方法三:
ifconfig ens33 |grep netmask|grep -Eo '([0-9]{1,3}.){4}'|head -n1

1.5 扩展正则

grep     -E     开启扩展正则

egrep     默认使用的 是扩展正则

*         匹配前面字符任意次
?         0或1次
+         1次或多次
{n}       匹配n次
{m,n}     至少m,至多n次
{,n}      #匹配前面的字符至多n次,<=n,n可以为0
{n,}      #匹配前面的字符至少n次,<=n,n可以为0

表示分组

() 分组
分组:() 将多个字符捆绑在一起,当作一个整体处理,如:\(root\)+
后向引用:\1, \2, ...
| 或者  
a|b #a或b
C|cat #C或cat
(C|c)at #Cat或cat

扩展正则中这些元字符可直接使用:
?

+

{

}

|

(

)

基础正则中这些元字符前需要加反斜线转义:
\?

\+

\{

\}

\|

\(

\)

grep -E 实例:

[root@localhost data]#echo abcabcabc|grep "(abc){3}"
#输入此命令无法过滤 ,因为基础正则无法识别 (){},可以在前面加上转义符或使用扩展正则。

[root@localhost data]#echo abcabcabc|grep "\(abc\)\{3\}"
abcabcabc


[root@localhost data]#echo abcabcabc|grep -E "(abc){3}"
abcabcabc
1、表示qq号
[root@localhost ~]#echo "940132245" |grep "\b[0-9]\{6,12\}\b"

#要加\b 如果不加要是有其它跟qq号一样格式的数并且前面还带字母,这样也会被匹配进去

如:
[root@localhost data]#echo "awf940132245" |grep "[0-9]\{6,12\}"
awf940132245
#匹配了一个和qq号无关的数。

[root@localhost data]#echo "awf940132245" |grep "\b[0-9]\{6,12\}\b"
[root@localhost data]#
#可以看到没有匹配成功。

[root@localhost data]#echo "awf 940132245" |grep "\b[0-9]\{6,12\}\b"
awf 940132245




2、表示邮箱
echo "zhou@qq.com" |grep -E "[[:alnum:]_-]+@[[:alnum:]_]+\.[[:alnum:]_]+"


3、表示手机号
echo "13705173391"|grep -E "\b1[3456789][0-9]{9}\b"
正则表达式的匹配过程

每一轮正则的匹配,都需要从正则的第一个元素从头开始匹配

第一轮匹配:

  • 扫描第一个字符,和正则表达式的第一个元素进行匹配
  • 如果匹配失败,则意味着这一轮的正则匹配失败

第二轮匹配:

  • 扫描下一个字符,从头开始和正则表达式进行匹配
  • 如果匹配成功,则继续扫描下一个字符和正则表达式的下一个元素进行匹配

        如果这个字符匹配失败,则导致这一轮正则匹配失败

        交还除第二轮匹配开始的首字符外的所有字符

        交还之后,从交还的第一个字符开始进入下一轮匹配

第三轮匹配:

  • 如果这一轮正则匹配成功,则不交还匹配成功的字符
  • 然后从匹配成功的下一个字符进入下一轮匹配

字符消耗问题

  • 某轮正则匹配成功,则消耗所有匹配成功的字符
  • 某轮匹配失败,则消耗本轮匹配的首字符,剩余的字符被交还

grep 基本使用

格式:grep   [选项]…   查找条件   目标文件

选项:

-m   数字 匹配的行数,匹配#次后停止
-i

忽略字符大小写

-n

显示匹配的行号

-c

统计匹配的行数

-o

仅显示匹配到的字符串(仅显示匹配的内容)

-q

静默模式,不输出任何信息(写脚本用)

-f

匹配两个文件相同的行   grep -f  A  B

-r

递归目录,但不处理软链接     开始搜索目录

-R

递归目录,但处理软链接

-w

匹配整个单词

-A    数字 显示匹配行及后 数字 行(如:后3行)
-B   数字 显示匹配行及前 数字 行(如:前3行)
-C   数字 显示匹配行及前后 数字 行(如:前3行和后3行)
-E

使用ERE(扩展正则),相当于egrep

-F

不支持正则表达式,相当于fgrep

-e 实现多个选项间的逻辑or关系,如:grep –e ‘cat ‘ -e ‘dog’ file    包含cat或者包含dog的行

关于grep -m

[root@localhost ~]#grep -m 1 da /etc/passwd   #多个匹配只取第一个
daemon:x:2:2:daemon:/sbin:/sbin/nologin

[root@localhost ~]#grep -m 2 da /etc/passwd    #多个匹配只取两个
daemon:x:2:2:daemon:/sbin:/sbin/nologin
libstoragemgmt:x:998:996:daemon account for libstoragemgmt:/var/run/lsm:/sbin/nologin

关于-A ,-B ,-C

grep -A  3 root  /etc/passwd  #匹配到的行后3行业显示出来

[root@localhost ~]#grep -A3 root /etc/passwd
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
--
operator:x:11:0:operator:/root:/sbin/nologin
games:x:12:100:games:/usr/games:/sbin/nologin
ftp:x:14:50:FTP User:/var/ftp:/sbin/nologin
nobody:x:99:99:Nobody:/:/sbin/nologin



grep -B  3 games  /etc/passwd    #匹配到的行前3行业显示出来

[root@localhost ~]#grep -B3 games /etc/passwd
halt:x:7:0:halt:/sbin:/sbin/halt
mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
operator:x:11:0:operator:/root:/sbin/nologin
games:x:12:100:games:/usr/games:/sbin/nologin



grep -C  2 games  /etc/passwd  #匹配到的行前2行 后2行业显示出来

[root@localhost ~]#grep -C2 games /etc/passwd
mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
operator:x:11:0:operator:/root:/sbin/nologin
games:x:12:100:games:/usr/games:/sbin/nologin
ftp:x:14:50:FTP User:/var/ftp:/sbin/nologin
nobody:x:99:99:Nobody:/:/sbin/nologin

关于 -w 

[root@localhost ~]#grep  r..t /etc/passwd    #过滤出r和t之间有两个字符的行
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@localhost ~]#grep -w r..t /etc/passwd   #过滤出r和t之间有两个字符 单词 的行
root:x:0:0:root:/root:/bin/bash
operator:x:11:0:operator:/root:/sbin/nologin


[root@localhost ~]#useradd rooter
[root@localhost ~]#grep  root /etc/passwd
root:x:0:0:root:/root:/bin/bash
operator:x:11:0:operator:/root:/sbin/nologin
rooter:x:1003:1003::/home/rooter:/bin/bash
[root@localhost ~]#grep -w root /etc/passwd     #过滤出只有root整个单词的行
root:x:0:0:root:/root:/bin/bash
operator:x:11:0:operator:/root:/sbin/nologin

 其它:

[root@test1 opt]# cat 123.txt |grep -v '^$' >test.txt  //将非空行写入到test.txt文件
[root@test1 opt]# grep "^b" 123.txt    //过滤已b开头
[root@test1 opt]#grep '/$'  123.txt    //过滤已/结尾
[root@test1 opt]# grep -v "^$" 123.txt //过滤非空行3 备份与

[root@localhost yum.repos.d]# ifconfig ens33 |grep -o "[0-9]\+\.[0-9]\+\.[0-9]\+\.[0-9]\+"
192.168.91.100
255.255.255.0
192.168.91.255
[root@localhost yum.repos.d]# ifconfig ens33 |grep -o "[0-9]\+\.[0-9]\+\.[0-9]\+\.[0-9]\+"|head -1
192.168.91.100


###面试题  统计当前主机的连接状态
[root@localhost ~]# ss -nta | grep -v '^State' |cut -d" " -f1|sort |uniq -c
      3 ESTAB
     17 LISTEN
#####统计当前连接主机数
[root@localhost ~]#ss -nt |tr -s " "|cut -d " " -f5|cut -d ":" -f1 |sort|uniq -c
      3 192.168.91.1
      1 192.168.91.101
      1 Address

本文来自网络,不代表协通编程立场,如若转载,请注明出处:https://net2asp.com/367e893f9e.html