Linux之正则表达式

正则表达式:定义的模式模板(pattern template),Linux工具可以用它来过滤文本。
如果匹配了定义的模式,它就会被接受并进一步处理;如果数据不匹配模式,它就会被滤掉。
在Linux中,有两种流行的正则表达式引擎:
 POSIX基础正则表达式(basic regular expression, BRE)引擎
 POSIX扩展正则表达式(extended regular expression, ERE)引擎

BRE模式--纯文本
正则表达式第一条原则就是:'正则表达式模式都区分大小写。

$ echo "The books are expensive" | sed -n '/book/p'
The books are expensive

BRE模式--特殊字符
正则表达式识别的特殊字符包括:

.*[]^${}\+?|()

特殊字符作为文本字符,就必须转义,转义字符:是反斜线(\)。

$ echo "3 / 2" | sed -n '/\//p'
3 / 2

BRE模式--锚字符

  1. 锁定在行首
    脱字符(^)定义从数据流中文本行的行首开始的模式。
$ echo "This ^ is a test" | sed -n '/s ^/p'
This ^ is a test

// 如果指定正则表达式模式时只用了脱字符,就不需要用反斜线来转义。但如果你在模式中先指定了脱字符,随后还有其他一些文本,那么你必须在脱字符前用转义字符。

  1. 锁定在行尾
    特殊字符美元符($)定义了行尾锚点。
$ echo "This is a good book" | sed -n '/book$/p'
This is a good book

// 要想匹配,文本模式必须是行的最后一部分。比如 sed -n '/boo$/p' 就不能实现匹配

  1. 组合锚点
    行首和行尾同时使用。
$ cat data5
This is one test line.
This is another test line.
$ sed '/^$/d' data5
This is one test line.
This is another test line.

BRE模式--点号字符
特殊字符点号用来匹配除换行符之外的任意单个字符。它必须匹配一个字符,如果在点号字符的位置没有字符,那么模式就不成立。

$ cat data6
This is a test of a line.
The cat is sleeping.
That is a very nice hat.
This test is at line four.
at ten o'clock we'll go home.
$ sed -n '/.at/p' data6
The cat is sleeping.
That is a very nice hat.
This test is at line four.
// 'cat' 'hat' ' at' 都可以匹配;而'a t'不能匹配。

BRE模式--字符组
字符组中必须有个字符来匹配相应的位置。

$ cat data7
This line doesn't contain a number.
This line has 1 number on it.
This line a number 2 on it.
This line has a number 4 on it.
$ sed -n '/[0123]/p' data7
This line has 1 number on it.
This line a number 2 on it.

如果要确保只匹配五位数,就必须将匹配的字符和其他字符分开,要么用空格,要么指明它们就在行首和行尾。

$ sed -n '
> /^[0123456789][0123456789][0123456789][0123456789][0123456789]$/p
> ' data8
60633
46201
22203
// 过滤出data8中只有5个字符的邮编。

字符组的一个极其常见的用法是"解析拼错的单词",比如用户表单输入的数据。

$ cat data9
I need to have some maintenence done on my car.
I'll pay that in a seperate invoice.
After I pay for the maintenance my car will be as good as new.
$ sed -n '
> /maint[ea]n[ae]nce/p
> /sep[ea]r[ea]te/p
> ' data9
I need to have some maintenence done on my car.
I'll pay that in a seperate invoice.
After I pay for the maintenance my car will be as good as new.

BRE模式--排除型字符组
可以寻找组中没有的字符,而不是去寻找组中含有的字符。

$ sed -n '/[^ch]at/p' data6
This test is at line four.

BRE模式--特殊的字符组
组 描 述

[[:alpha:]] 匹配任意字母字符,不管是大写还是小写
[[:alnum:]] 匹配任意字母数字字符0~9、 A~Z或a~z
[[:blank:]] 匹配空格或制表符
[[:digit:]] 匹配0~9之间的数字
[[:lower:]] 匹配小写字母字符a~z
[[:print:]] 匹配任意可打印字符
[[:punct:]] 匹配标点符号
[[:space:]] 匹配任意空白字符:空格、制表符、 NL、 FF、 VT和CR
[[:upper:]] 匹配任意大写字母字符A~Z
$ echo "abc" | sed -n '/[[:digit:]]/p'
$
$ echo "abc" | sed -n '/[[:alpha:]]/p'
abc
$ echo "abc123" | sed -n '/[[:digit:]]/p'
abc123
$ echo "This is, a test" | sed -n '/[[:punct:]]/p'
This is, a test

BRE模式--区间

可以用单破折线符号在字符组中表示字符区间。

$ sed -n '/^[0-9][0-9][0-9][0-9][0-9]$/p' data8
60633
46201
45902

也适用于字母。

$ sed -n '/[c-h]at/p' data6
The cat is sleeping.
That is a very nice hat.

可以在单个字符组指定多个不连续的区间。

$ sed -n '/[a-ch-m]at/p' data6
The cat is sleeping.
That is a very nice hat.

BRE模式--星号
在字符后面放置星号表明该字符必须在匹配模式的文本中出现0次或多次。

$ echo "I ate a potatoe with my lunch." | sed -n '/potatoe*/p'
I ate a potatoe with my lunch.

将点号特殊字符和星号特殊字符组合起来。这个组合能够匹配任意数量的任意字符。它通常用在数据流中两个可能相邻或不相邻的文本字符串之间。

$ echo "this is a regular pattern expression" | sed -n '
> /regular.*expression/p'
this is a regular pattern expression

扩展--问号
问号表明前面的字符可以出现0次或1次,但只限于此。它不会匹配多次出现的字符。

$ echo "bt" | gawk '/be?t/{print $0}'
bt
$ echo "bet" | gawk '/be?t/{print $0}'
bet

扩展--加号
加号表明前面的字符可以出现1次或多次,但必须至少出现1次。如果该字符没有出现,那么模式就不会匹配。

$ echo "beeet" | gawk '/be+t/{print $0}'
beeet
$ echo "beet" | gawk '/be+t/{print $0}'
beet
$ echo "bet" | gawk '/be+t/{print $0}'
bet
$ echo "bt" | gawk '/be+t/{print $0}'
$

扩展--花括号
间隔(interval),可以用两种格式来指定区间。
 m:正则表达式准确出现m次。
 m, n:正则表达式至少出现m次,至多n次。
这个特性可以精确调整字符或字符集在模式中具体出现的次数。
// 默认情况下, gawk程序不会识别正则表达式间隔。必须指定gawk程序的--re- interval命令行选项才能识别正则表达式间隔。

$ echo "bt" | gawk --re-interval '/be{1}t/{print $0}'
$
$ echo "bet" | gawk --re-interval '/be{1}t/{print $0}'
bet
$ echo "beet" | gawk --re-interval '/be{1}t/{print $0}'
$

字符e可以出现1次或2次,这样模式就能匹配;否则,模式无法匹配:

$ echo "bet" | gawk --re-interval '/be{1,2}t/{print $0}'
bet
$ echo "beet" | gawk --re-interval '/be{1,2}t/{print $0}'
beet

扩展--管道符号
管道符号允许你在检查数据流时,用逻辑OR方式指定正则表达式引擎要用的两个或多个模式。
使用管道符号的格式如下:

    expr1|expr2|...
$ echo "The cat is asleep" | gawk '/cat|dog/{print $0}'
The cat is asleep
$ echo "The dog is asleep" | gawk '/cat|dog/{print $0}'
The dog is asleep
$ echo "The sheep is asleep" | gawk '/cat|dog/{print $0}'
$

这个例子会匹配数据流文本中的cat、 hat或dog。

$ echo "He has a hat." | gawk '/[ch]at|dog/{print $0}'
He has a hat.

扩展--表达式分组
可以用圆括号()进行分组。

$ echo "Sat" | gawk '/Sat(urday)?/{print $0}'
Sat
$ echo "Saturday" | gawk '/Sat(urday)?/{print $0}'
Saturday

结尾的urday分组以及问号,使得模式能够匹配完整的Saturday或缩写Sat。
将分组和管道符号一起使用来创建可能的模式匹配组是很常见的做法:

$ echo "cat" | gawk '/(c|b)a(b|t)/{print $0}'
cat
$ echo "cab" | gawk '/(c|b)a(b|t)/{print $0}'
cab
$ echo "bat" | gawk '/(c|b)a(b|t)/{print $0}'
bat
$ echo "bab" | gawk '/(c|b)a(b|t)/{print $0}'
bab
$ echo "tab" | gawk '/(c|b)a(b|t)/{print $0}'
$
$ echo "tac" | gawk '/(c|b)a(b|t)/{print $0}'
$

总结与补充

基本正则

grep 'partern'

扩展正则

grep -E 'partern'

perl正则(更强的正则)

grep -P 'partern'

1.必记的常用元字符:

.匹配除换行符以外的任意字符
\w 匹配字母或数字或下划线或汉字 \W表示与之相反
\s匹配任意的空白符\S表示与之相反
\d匹配数字\D表示与之相反
\b匹配单词的开始或结束\B表示与之相反
^匹配字符串的开始
$匹配字符串的结束
[x] 匹配字符x [^x]表示出来字符x以外的任意字符
[aeiou] 匹配英语中的元音字母 [^aeiou]表示除了元音字母以外的所有字符

实例

[root@hadoop ~]# cat test.txt
hello
998

@#$
44.5
nihao ll
[root@hadoop ~]# cat test.txt | grep -P '\w'
hello
998
44.5
nihao ll
[root@hadoop ~]# cat test.txt | grep -P '\W'
@#$
44.5
nihao ll
[root@hadoop ~]# cat test.txt | grep -P '\s'
nihao ll
[root@hadoop ~]# cat test.txt | grep -P '\S'
hello
998
@#$
44.5
nihao ll
[root@hadoop ~]# cat test.txt | grep -P '\d'
998
44.5
[root@hadoop ~]# cat test.txt | grep -P '\D'
hello
@#$
44.5
nihao ll
[root@hadoop ~]# cat test.txt | grep -P '\b'
hello
998
44.5
nihao ll
[root@hadoop ~]# cat test.txt | grep -P '\B'
hello
998

@#$
44.5
nihao ll
[root@hadoop ~]# cat test.txt | grep -P '^$'

[root@hadoop ~]# 

2.必记的常用限定符

* 重复零次或更多次
+ 重复一次或更多次
? 重复零次或一次
{n} 重复n次
{n,} 重复n次或更多次
{n,m} 重复n到m次

3.必记的常用分组语法

小括号表示一个子表达式,匹配这个子表达式也就是捕获匹配到的文本,默认情况下,每个分组会自动拥有一个组号,

规则是:从左向右,以分组的左括号为标志,第一个出现的分组的组号为1,第二个为2,以此类推,
组号分配过程是要从左向右扫描两遍的:第一遍只给未命名组分配,第二遍只给命名组分配--因此所有命名组的组号都大于未命名的组号

3.1捕获
(exp) 匹配exp,并捕获文本到自动命名的组里 \b(\w+)\b\s+\1\b可以用来匹配重复的单词,像go go, 或者kitty kitty

[root@hadoop ~]# echo 'kitty kitty' | grep -oE '\b(\w+)\b\s+\1\b'
kitty kitty

(?<name>exp)匹配exp,并捕获文本到名称为name的组里,也可以写成(?'name'exp)

上面的正则指定组名,可以写成\b(?<Word>\w+)\b\s+\k<Word>\b
(?:exp) 匹配exp,不捕获匹配的文本,也不给此分组分配组号

[root@hadoop ~]# echo 'kitty kitty' | grep -oP '\b(?<wox>\w+)\b\s+\k<wox>\b'
kitty kitty

(?:@\w)binguo\w匹配@开头包含binguo的字符串
(?:exp)不会改变正则表达式的处理方式,只是这样的组匹配的内容不会像前两种那样被捕获到某个组里面,也不会拥有组号

3.2零宽断言
(?=exp) 匹配exp前面的位置
\b\w+(?=ing\b) I'm singing while you're dancing 匹配sing和danc

(?<=exp)匹配exp后面的位置
(?<=\bre)\w+\b reading a book 匹配ading

[root@hadoop ~]# ifconfig | grep -oP '(?<=inet addr:).*(?=Bcast)'
192.168.121.128  
[root@hadoop ~]# ifconfig | grep -oP '(?=inet addr:).*(?<=Bcast)'
inet addr:192.168.121.128  Bcast
[root@hadoop ~]# ifconfig | grep -oP '(?<=inet addr:).*(?<=Bcast)'
192.168.121.128  Bcast

(?<=\s)\d+(?=\s)匹配以空白符间隔的数字(再次强调,不包括这些空白符)

[root@hadoop ~]# echo "nihao 9527 hello" | grep -P '(?<=\s)\d+(?=\s)'
nihao 9527 hello

(?!exp) 匹配后面跟的不是exp的位置
需求:获取不是.exe后缀文件不含后缀的文件名

[root@hadoop ~]# cat files.test 
notexefile1.txt
exefile1.exe
exefile2.exe
exefile3.exe
notexefile2.php
notexefile3.sh
[root@hadoop ~]# cat files.test | grep -oP '(.+)(?!\.exe)\.[\S]+$'
notexefile1.txt
notexefile2.php
notexefile3.sh

(?<!exp)匹配前面不是exp的位置
需求:获取不是name参数的值

[root@hadoop ~]# cat form.txt 
name=zhangsan
password=123456
---------------
age=26
sex=man
[root@hadoop ~]# cat form.txt | grep -oP '^[^=]+=(?<!name=)(.+)'
password=123456
age=26
sex=man

3.3注释
(?#comment)这种类型的分组不对正则表达式的处理产生任何影响,用于提供注释让人阅读

4.必记的懒惰限定符
*? 重复任意次,但尽可能少重复
+? 重复1次或更多次,但尽可能少重复

贪婪匹配:在使整个表达式能得到匹配的前提下,匹配尽可能多的字符
a.*b,它将会匹配最长的以a开始,以b结束的字符串。如果用它来搜索aabab的话,它会匹配整个字符串aabab。

懒惰(非贪婪)匹配:

也就是匹配尽可能少的字符,《2.必记的常用限定符》提到的限定符都可以被转化为懒惰匹配模式,只要在它后面加上一个问号?
a.*?b,匹配最短的,以a开始,以b结束的字符串。

如果把它应用于aabab的话,它会匹配aab(第一到第三个字符)和ab(第四到第五个字符)
为什么第一个匹配的是aab(第一到第三个字符)而不是ab(第二到第三个字符)?
简单地说,因为正则表达式有另一条规则,比懒惰/贪婪规则的优先级更高:最先开始的匹配拥有最高的优先权

[root@hadoop ~]# echo '<div>test1</div>bb<div>test2</div>' | grep -oP '<div>.*</div>'
<div>test1</div>bb<div>test2</div>
[root@hadoop ~]# echo '<div>test1</div>bb<div>test2</div>' | grep -oP '<div>.*?</div>'
<div>test1</div>
<div>test2</div>

参考正则表达式30分钟入门教程

闯关模式实践

http://regex.alf.nu 闯关模式练习正则表达式,完成一个个正则匹配的测验
http://regexone.com/ 通过实际练习掌握正则表达式
https://regexcrossword.com/ 正则挑战,有不同难度,很丰富
http://callumacrae.github.io/regex-tuesday/ 正则挑战,完成正则匹配要求

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,294评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,493评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,790评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,595评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,718评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,906评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,053评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,797评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,250评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,570评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,711评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,388评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,018评论 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,796评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,023评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,461评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,595评论 2 350

推荐阅读更多精彩内容

  • 正则表达式:定义的模式模板(pattern template),Linux工具可以用它来过滤文本。如果匹配了定义的...
    piziyang12138阅读 396评论 0 0
  • 正则表达式:定义的模式模板(pattern template),Linux工具可以用它来过滤文本。如果匹配了定义的...
    数据萌新阅读 188评论 0 0
  • 正则表达式:定义的模式模板(pattern template),Linux工具可以用它来过滤文本。如果匹配了定义的...
    Arroganter阅读 264评论 0 0
  • 正则表达式到底是什么东西?字符是计算机软件处理文字时最基本的单位,可能是字母,数字,标点符号,空格,换行符,汉字等...
    狮子挽歌阅读 2,141评论 0 9
  • 我签到了,同桌也签了。——万无一失 早上看大合唱 晚上画了一会画 吃了廋肉粉 和✘✘聊了一下
    逆风追梦人阅读 164评论 0 0