# 正则表达式（7）：扩展正则表达式

- 23

- A+

所属分类：Linux基础

> 在本博客中，"正则表达式"为一系列文章，如果你想要从头学习怎样在Linux中使用正则，可以参考此系列文章，直达链接如下：

> 在Linux中使用正则表达式

> "正则"系列的每篇文章都建立在前文的基础之上，所以，请按照顺序阅读这些文章，否则有可能在阅读中遇到障碍。

前文中一直在说，在Linux中，正则表达式可以分为"基本正则表达式"和"扩展正则表达式"。

我们已经认识了"基本正则表达式"，现在，我们来认识一下"扩展正则表达式"。

有了之前的基础，学习"扩展正则表达式"简直不要太轻松。

之前说过，有些符号是通用的，不管是在"基本正则表达式"中，还是在"扩展正则表达式"中，这些通用的符号所表达的意思都是相同的。

那么，我们先来看看哪些符号是通用的，看完之后你会信心大增，如下字符都是通用的：

Shell
. 表示任意单个字符。 * 表示前面的字符连续出现任意次，包括0次。 .* 表示任意长度的任意字符，与通配符中的*的意思相同。 \ 表示转义符，当与正则表达式中的符号结合时表示符号本身。 [ ]表示匹配指定范围内的任意单个字符。 [^ ]表示匹配指定范围外的任意单个字符。 [[:alpha:]] 表示任意大小写字母。 [[:lower:]] 表示任意小写字母。 [[:upper:]] 表示任意大写字母。 [[:digit:]] 表示0到9之间的任意单个数字（包括0和9）。 [[:alnum:]] 表示任意数字或字母。 [[:space:]] 表示任意空白字符，包括"空格"、"tab键"等。 [[:punct:]] 表示任意标点符号。 [^[:alpha:]] 表示单个非字母字符。 [^[:lower:]] 表示单个非小写字母字符。 [^[:upper:]] 表示单个非大写字母字符。 [^[:digit:]] 表示单个非数字字符。 [^[:alnum:]] 表示单个非数字非字母字符。 [^[:space:]] 表示单个非空白字符。 [^[:punct:]] 表示单个非标点符号字符。 [0-9]与[[:digit:]]等效。 [a-z]与[[:lower:]]等效。 [A-Z]与[[:upper:]]等效。 [a-zA-Z]与[[:alpha:]]等效。 [a-zA-Z0-9]与[[:alnum:]]等效。 [^0-9]与[^[:digit:]]等效。 [^a-z]与[^[:lower:]]等效。 [^A-Z]与[^[:upper:]]等效 [^a-zA-Z]与[^[:alpha:]]等效 [^a-zA-Z0-9]与[^[:alnum:]]等效 ^：表示锚定行首，此字符后面的任意内容必须出现在行首，才能匹配。 $：表示锚定行尾，此字符前面的任意内容必须出现在行尾，才能匹配。 ^$：表示匹配空行，这里所描述的空行表示"回车"，而"空格"或"tab"等都不能算作此处所描述的空行。 ^abc$：表示abc独占一行时，会被匹配到。 \<或者\b ：匹配单词边界，表示锚定词首，其后面的字符必须作为单词首部出现。 \>或者\b ：匹配单词边界，表示锚定词尾，其前面的字符必须作为单词尾部出现。 \B：匹配非单词边界，与\b正好相反。

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 | . 表示任意单个字符。 * 表示前面的字符连续出现任意次，包括0次。 .* 表示任意长度的任意字符，与通配符中的*的意思相同。 \ 表示转义符，当与正则表达式中的符号结合时表示符号本身。 [ ]表示匹配指定范围内的任意单个字符。 [^ ]表示匹配指定范围外的任意单个字符。 [[:alpha:]] 表示任意大小写字母。 [[:lower:]] 表示任意小写字母。 [[:upper:]] 表示任意大写字母。 [[:digit:]] 表示0到9之间的任意单个数字（包括0和9）。 [[:alnum:]] 表示任意数字或字母。 [[:space:]] 表示任意空白字符，包括"空格"、"tab键"等。 [[:punct:]] 表示任意标点符号。 [^[:alpha:]] 表示单个非字母字符。 [^[:lower:]] 表示单个非小写字母字符。 [^[:upper:]] 表示单个非大写字母字符。 [^[:digit:]] 表示单个非数字字符。 [^[:alnum:]] 表示单个非数字非字母字符。 [^[:space:]] 表示单个非空白字符。 [^[:punct:]] 表示单个非标点符号字符。 [0-9]与[[:digit:]]等效。 [a-z]与[[:lower:]]等效。 [A-Z]与[[:upper:]]等效。 [a-zA-Z]与[[:alpha:]]等效。 [a-zA-Z0-9]与[[:alnum:]]等效。 [^0-9]与[^[:digit:]]等效。 [^a-z]与[^[:lower:]]等效。 [^A-Z]与[^[:upper:]]等效 [^a-zA-Z]与[^[:alpha:]]等效 [^a-zA-Z0-9]与[^[:alnum:]]等效 ^：表示锚定行首，此字符后面的任意内容必须出现在行首，才能匹配。 $：表示锚定行尾，此字符前面的任意内容必须出现在行尾，才能匹配。 ^$：表示匹配空行，这里所描述的空行表示"回车"，而"空格"或"tab"等都不能算作此处所描述的空行。 ^abc$：表示abc独占一行时，会被匹配到。 \<或者\b ：匹配单词边界，表示锚定词首，其后面的字符必须作为单词首部出现。 \>或者\b ：匹配单词边界，表示锚定词尾，其前面的字符必须作为单词尾部出现。 \B：匹配非单词边界，与\b正好相反。

上述符号，在基本正则表达式中与扩展正则表达式中的用法完全相同。

有没有感觉，70%都是通用的，那么我们来动手试试。

在总结grep命令时，我们提到过，grep命令默认只支持基本正则表达式，如果想要让grep命令能够支持扩展的正则表达式，则需要使用"-E"选项，示例如下

上图中，grep命令使用了"-E"选项，表示grep命令会把"正则表达式"中的符号当成"扩展正则表达式"去理解，而不再使用默认的"基本正则表达式"。

但是由于"[A-Z]"是通用的，所以，不管是否使用扩展正则表达式，"[A-Z]"都表示单个大写字母。

刚才说过，70%的符号都是通用的，那么剩下的30%呢？

其实，剩下的30%也都差不多，与基本正则表达式相比，反而更加简单了，不信？我们就来看看。

在基本正则表达式中，\{n\} 表示前面的字符连续出现n次，将会被匹配到。

在扩展正则表达式中，{n} 表示前面的字符连续出现n次，将会被匹配到。

在基本正则表达式中，\( \) 表示分组，\(ab\) 表示将ab当做一个整体去处理。

在扩展正则表达式中，( ) 表示分组，(ab) 表示将ab当做一个整体去处理。

在写法上，"扩展正则表达式"的写法是不是更加简练呢？示例如下

如上图所示，当使用"扩展正则表达式"时，在"书写"方面，反而省力不少，最终匹配到的文本却是相同的，是不是很方便？

看完了上述示例，我想你对扩展正则表达式应该已经有了一个初步的印象了。

那么，我们就来介绍一下，有哪些符号在"扩展正则表达式"中变得更加简练了。

在扩展正则表达式中：

( ) 表示分组

(ab) 表示将ab当做一个整体去处理。

\1 表示引用整个表达式中第1个分组中的正则匹配到的结果。

\2 表示引用整个表达式中第2个分组中的正则匹配到的结果。

? 表示匹配其前面的字符0或1次

+ 表示匹配其前面的字符至少1次，或者连续多次，连续次数上不封顶。

{n} 表示前面的字符连续出现n次，将会被匹配到。

{x,y} 表示之前的字符至少连续出现x次，最多连续出现y次，都能被匹配到，换句话说，只要之前的字符连续出现的次数在x与y之间，即可被匹配到。

{,n} 表示之前的字符连续出现至多n次，最少0次，都会陪匹配到。

{n,}表示之前的字符连续出现至少n次，才会被匹配到。

看了上述总结以后，是不是已经想要放弃使用"基本正则表达式"了呢？因为与之相比，扩展正则表达式才更符合我们这些懒人的习惯，而且，扩展正则表达式的可读性也更高，毕竟很多符号少了前面的"\"，可读性就变强了。

扩展正则表达式中，还有一个常用的符号，是基本正则表达式中所没有的，它就是"|"

注：按住键盘的 "shift键" 和 "\"键 ，就可以打出"|"

"|"在扩展正则表达式中，表示"或"，这样说不容易理解，我们来看个小例子，就能明白，示例文件内容如下。

如果，我们想要从上例文本中找到以"com"结尾的行，我们该怎么办呢？我们可以使用如下命令。

同理，如果我们想要从示例文本中找出以"net"结尾的行，可以使用如下命令。

那么，如果我们想要从示例文本找出，以"com"结尾，或者以"net"结尾的行，我们该怎么办呢？

这时候，我们就需要用到"|"

"|"在扩展正则表达式中表示"或者"，所以，我们可以使用如下表达式

上图中的扩展正则使用了分组符号"( )"，"(com|net)"表示将括号内的内容看做一个整体，而括号内的内容为"com|net"，它表示"com或者net"，所以，"(com|net)$"就表示以com或者net结尾的行。是不是很简单？

那么，我们就趁热打铁，通过实际练习，来熟悉一下"扩展正则表达式"吧。

仍然以刚才的示例文件作为测试文件，假设，我们想要查找出测试文本中的"合法邮箱"，我们应该怎么做呢？

既然是要找出"合法邮箱"，那么，我们则必须事先定义，满足哪些条件的邮箱才属于合法邮箱。

所以，我们规定，如果一个邮箱属于合法邮箱，那么必须满足如下条件。

1、邮箱字符串中必须包含"@"符。

2、"@"符前面的字符只能是小写字母或数字，不能包含特殊符号。

3、"@"符前面的字符数量至少需要4个，至多为16个。

4、邮箱必须以"com"、"net"、"org"、"edu"等顶级域名结尾（此处为了方便演示，不判断更多的域名）。

5、顶级域名之前必须包含一个"点"，换句话说就是，邮箱必须以".com"、".net"、".org"、".edu"结尾。

6、"@"与"."之间的字符数量不能超过12个，不能低于2个。

7、"@"与"."之间的字符只能是小写字母或数字，不能包含特殊符号。

好了，了解了合法邮箱的规则以后，我们就可以开始编写正则表达式了，我们可以使用如下正则，查找文本中的合法邮箱。

如果你觉得上述正则稍微有些复杂，不容易理解，那么可以将其拆分成几个部分去理解，拆分后的每一部分，可以与之前的"合法邮箱条件"一一对应，如下图所示。

这样看，是不是容易理解多了，好了，赶快自己动手实验一下吧。

## 小结

我认为，有了之前基础的你，搞定"扩展正则表达式"，肯定是分分钟的事情，所以，我们就对"扩展正则表达式"进行一下总结吧。

Shell
常用符号 . 表示任意单个字符。 * 表示前面的字符连续出现任意次，包括0次。 .* 表示任意长度的任意字符，与通配符中的*的意思相同。 \ 表示转义符，当与正则表达式中的符号结合时表示符号本身。 | 表示"或者"之意 [ ]表示匹配指定范围内的任意单个字符。 [^ ]表示匹配指定范围外的任意单个字符。 单个字符匹配相关 [[:alpha:]] 表示任意大小写字母。 [[:lower:]] 表示任意小写字母。 [[:upper:]] 表示任意大写字母。 [[:digit:]] 表示0到9之间的任意单个数字（包括0和9）。 [[:alnum:]] 表示任意数字或字母。 [[:space:]] 表示任意空白字符，包括"空格"、"tab键"等。 [[:punct:]] 表示任意标点符号。 [^[:alpha:]] 表示单个非字母字符。 [^[:lower:]] 表示单个非小写字母字符。 [^[:upper:]] 表示单个非大写字母字符。 [^[:digit:]] 表示单个非数字字符。 [^[:alnum:]] 表示单个非数字非字母字符。 [^[:space:]] 表示单个非空白字符。 [^[:punct:]] 表示单个非标点符号字符。 [0-9]与[[:digit:]]等效。 [a-z]与[[:lower:]]等效。 [A-Z]与[[:upper:]]等效。 [a-zA-Z]与[[:alpha:]]等效。 [a-zA-Z0-9]与[[:alnum:]]等效。 [^0-9]与[^[:digit:]]等效。 [^a-z]与[^[:lower:]]等效。 [^A-Z]与[^[:upper:]]等效 [^a-zA-Z]与[^[:alpha:]]等效 [^a-zA-Z0-9]与[^[:alnum:]]等效 次数匹配相关 ? 表示匹配其前面的字符0或1次 + 表示匹配其前面的字符至少1次，或者连续多次，连续次数上不封顶。 {n} 表示前面的字符连续出现n次，将会被匹配到。 {x,y} 表示之前的字符至少连续出现x次，最多连续出现y次，都能被匹配到，换句话说，只要之前的字符连续出现的次数在x与y之间，即可被匹配到。 {,n} 表示之前的字符连续出现至多n次，最少0次，都会陪匹配到。 {n,}表示之前的字符连续出现至少n次，才会被匹配到。 位置边界匹配相关 ^：表示锚定行首，此字符后面的任意内容必须出现在行首，才能匹配。 $：表示锚定行尾，此字符前面的任意内容必须出现在行尾，才能匹配。 ^$：表示匹配空行，这里所描述的空行表示"回车"，而"空格"或"tab"等都不能算作此处所描述的空行。 ^abc$：表示abc独占一行时，会被匹配到。 \<或者\b ：匹配单词边界，表示锚定词首，其后面的字符必须作为单词首部出现。 \>或者\b ：匹配单词边界，表示锚定词尾，其前面的字符必须作为单词尾部出现。 \B：匹配非单词边界，与\b正好相反。 分组与后向引用 ( ) 表示分组，我们可以将其中的内容当做一个整体，分组可以嵌套。 (ab) 表示将ab当做一个整体去处理。 \1 表示引用整个表达式中第1个分组中的正则匹配到的结果。 \2 表示引用整个表达式中第2个分组中的正则匹配到的结果。

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 | 常用符号 . 表示任意单个字符。 * 表示前面的字符连续出现任意次，包括0次。 .* 表示任意长度的任意字符，与通配符中的*的意思相同。 \ 表示转义符，当与正则表达式中的符号结合时表示符号本身。 | 表示"或者"之意 [ ]表示匹配指定范围内的任意单个字符。 [^ ]表示匹配指定范围外的任意单个字符。 单个字符匹配相关 [[:alpha:]] 表示任意大小写字母。 [[:lower:]] 表示任意小写字母。 [[:upper:]] 表示任意大写字母。 [[:digit:]] 表示0到9之间的任意单个数字（包括0和9）。 [[:alnum:]] 表示任意数字或字母。 [[:space:]] 表示任意空白字符，包括"空格"、"tab键"等。 [[:punct:]] 表示任意标点符号。 [^[:alpha:]] 表示单个非字母字符。 [^[:lower:]] 表示单个非小写字母字符。 [^[:upper:]] 表示单个非大写字母字符。 [^[:digit:]] 表示单个非数字字符。 [^[:alnum:]] 表示单个非数字非字母字符。 [^[:space:]] 表示单个非空白字符。 [^[:punct:]] 表示单个非标点符号字符。 [0-9]与[[:digit:]]等效。 [a-z]与[[:lower:]]等效。 [A-Z]与[[:upper:]]等效。 [a-zA-Z]与[[:alpha:]]等效。 [a-zA-Z0-9]与[[:alnum:]]等效。 [^0-9]与[^[:digit:]]等效。 [^a-z]与[^[:lower:]]等效。 [^A-Z]与[^[:upper:]]等效 [^a-zA-Z]与[^[:alpha:]]等效 [^a-zA-Z0-9]与[^[:alnum:]]等效 次数匹配相关 ? 表示匹配其前面的字符0或1次 + 表示匹配其前面的字符至少1次，或者连续多次，连续次数上不封顶。 {n} 表示前面的字符连续出现n次，将会被匹配到。 {x,y} 表示之前的字符至少连续出现x次，最多连续出现y次，都能被匹配到，换句话说，只要之前的字符连续出现的次数在x与y之间，即可被匹配到。 {,n} 表示之前的字符连续出现至多n次，最少0次，都会陪匹配到。 {n,}表示之前的字符连续出现至少n次，才会被匹配到。 位置边界匹配相关 ^：表示锚定行首，此字符后面的任意内容必须出现在行首，才能匹配。 $：表示锚定行尾，此字符前面的任意内容必须出现在行尾，才能匹配。 ^$：表示匹配空行，这里所描述的空行表示"回车"，而"空格"或"tab"等都不能算作此处所描述的空行。 ^abc$：表示abc独占一行时，会被匹配到。 \<或者\b ：匹配单词边界，表示锚定词首，其后面的字符必须作为单词首部出现。 \>或者\b ：匹配单词边界，表示锚定词尾，其前面的字符必须作为单词尾部出现。 \B：匹配非单词边界，与\b正好相反。 分组与后向引用 ( ) 表示分组，我们可以将其中的内容当做一个整体，分组可以嵌套。 (ab) 表示将ab当做一个整体去处理。 \1 表示引用整个表达式中第1个分组中的正则匹配到的结果。 \2 表示引用整个表达式中第2个分组中的正则匹配到的结果。

关于"扩展正则表达式"，就总结到这里，希望能够帮助到你~~

我的微信公众号
关注"实用运维笔记"微信公众号，当博客中有新文章时，可第一时间得知哦~
赞 45
赏
分享

- 正则表达式

- 版权声明：本站原创文章，于2017年6月9日10:34:24，由 朱双印 发表，共 2519 字。
- 如需转载，请在文章头部注明出处：正则表达式（7）：扩展正则表达式 | 朱双印博客

正则表达式（6）：基本正则表达式小结
正则表达式（5）：转义符
正则表达式（4）：分组与后向引用
正则表达式（3）：常用符号

### 发表评论取消回复

欢迎 pangzi 再次光临！
修改信息

正在提交, 请稍候...
#

昵称*

邮箱*

网址

有回复时邮件通知我

## 目前评论：23 其中：访客 18 博主 5

2. 勇气 1
   回复 2020年7月21日 下午2:43 沙发

   grep -E “[a-z0-9]{4,16}@[a-z0-9]{2,12}\.com$” mail.txt
   请问一下，我这个为什么匹配不到cccom结尾的呢？

4. 小白 1
   回复 2020年4月20日 下午3:45 板凳

   不太明白\. 与. 又有什么区别，()$ 与(())$有什么区别
   [monitor@linux quota]$ grep -E “[a-z0-9]{4,16}@[a-z0-9]{2,12}.(com|net|edu)$” REG -n
   1:zhang@163.com
   4:213213@net.com
   [monitor@linux quota]$ grep -E “[a-z0-9]{4,16}@[a-z0-9]{2,12}\.(com|net|edu)$” REG -n
   1:zhang@163.com
   4:213213@net.com
   [monitor@linux quota]$

   - 勇气 1
     回复 2020年7月21日 下午2:52 1层

     @小白 .代表的是任意一个字符，而 \. 使用了转义处理，代表的是字符.
     如果内容既有.com 还有#com的话，不加\既会匹配到.com，又可以匹配到#com
     [root@agent ~]# grep -E “[a-z0-9]{4,16}@[a-z0-9]{2,12}\.com$” mail.txt
     testregex@163.com
     [root@agent ~]#
     [root@agent ~]# grep -E “[a-z0-9]{4,16}@[a-z0-9]{2,12}.com$” mail.txt
     testregex@163.com
     testregex@163#com

6. 迷之夏天 3
   回复 2020年4月20日 下午12:01 地板

   打卡，博主帅

8. meme 0
   回复 2019年11月24日 下午10:58 4楼

   请问下楼主，如果要去匹配中文字符，应该怎么操作呢？好像没有讲到中文字符的提取呢

10. 陈飞 1
    回复 2019年9月23日 下午8:59 5楼

    本来想提问邮箱为什么加上\<,发现下面评论已经有了。
    多谢老师，写得很好

    - 朱双印 Admin
      回复 2019年9月24日 上午9:13 1层

      @陈飞 能帮到你就好，加油～

12. 弥彦 0
    回复 2019年7月12日 下午3:54 6楼

    有幸拜读，写的很好，加深了我对正则的认识，其实扩展正则跟一般程序语言中的正则很类似

14. skywind 1
    回复 2019年7月5日 上午11:26 7楼

    感谢🙏！这几天连续读了两遍，正则表达式没有比你介绍得更清楚了！希望能继续讲解其它常用命令，比如sed, xargs。

    - 朱双印 Admin
      回复 2019年7月6日 下午8:41 1层

      @skywind 嗯嗯，抽出空闲会在复习一下别的，重新总结一遍，加油~

16. rubuzhao 0
    回复 2019年6月28日 下午12:27 8楼

    条件4写成(com|net|org|edu)$和锚定词首的结果一样，老师这里加上\<是有什么考虑吗？

    - 朱双印 Admin
      回复 2019年6月28日 下午4:05 1层

      @rubuzhao 如果一样的话就是当时没有进行任何测试，为了保险，那样写的，当时应该是和评论中的”福长”同学的想法一样，如果测试了一样，就没有什么必要了，加油～～

18. zhoum 1
    回复 2019年3月22日 上午11:52 9楼

    我试了，可以不用词首瞄定符，求楼主解答。
    cat testd
    zhenguo@139.com
    zhenguo@163.net
    zhenguo@139.com.cn zhenguo@ss.net
    zhen@eeeeee.sssscom.org.net

    [root@localhost software]# grep -E “[0-9a-z]{4,16}@[a-z0-9]{2,12}\.(\<(com|net|edu|org))$" testd
    zhenguo@163.net
    zhenguo@139.com.cn zhenguo@ss.net
    [root@localhost software]# grep -E "[0-9a-z]{4,16}@[a-z0-9]{2,12}\.((com|net|edu|org))$" testd
    zhenguo@163.net

20. 别小严肃点 0
    回复 2019年1月9日 下午2:00 10楼

    正则表达式的修饰符，大神能介绍一下不

22. Pearl 2
    回复 2018年9月22日 下午5:40 11楼

    学海无涯啊

24. re 1
    回复 2017年11月28日 下午7:29 12楼

    条件4中一定要用/<锚定吗

    - wesharp 1
      回复 2018年8月6日 下午10:33 1层

      @re 同样的疑问

      - 福长 1
        回复 2018年12月30日 下午2:18 2层

        @wesharp “必须”二字看到了吗？如果不加\<的话，可能会以匹配到csadcom结尾

        - lnking 1
          回复 2019年1月31日 下午4:26 3层

          @福长 感觉可以不需要

26. yanan001 2
    回复 2017年6月16日 下午5:40 13楼

    [root@localhost regex]# ifconfig |grep -E ‘([0-9]{1,3}\.)\1([0-9]{1,3})’
    楼主你好，我输入如上命令，按道理应该是grep出IP地址前面192.168.122之类的，为什么结果不对呢？

    - 朱双印 Admin
      回复 2017年6月16日 下午6:06 1层

      @yanan001 正则写错了，没有必要用\1进行后向引用，用类似这样的表达式应该可以
      ([0-9]{1,3}\.){3}([0-9]{1,3})

28. echo 6
    回复 2017年6月12日 下午9:47 14楼

    以前是基本/扩展混淆用
    现在终于分开了

    - 朱双印 Admin
      回复 2017年6月12日 下午9:50 1层

      @echo 慢慢的就都清楚了，加油，兄弟

- 文章目录

×
×
拖拽到此处
图片将完成下载