在Linux中通常可以使用 grep 和 egrep 命令在文件中筛选字符,查找到你想要的结果。这两个命令的强大之处是可以结合正则表达式使用。那么什么是正则表达式?

正则表达式是一组使用单个字符串来描述、匹配一系列符合某个句法规则的字符串,正则表达式通常分为基本正则表达式和扩展正则表达式。grep命令可以使用基本的正则表达式作筛选,加上一个参数 -E 则可以使用扩展的正则表达式。而egrep则是使用扩展的正则表达式,用法和 grep -E 是一样的。那么现在就来说说正则表达式吧。


一、正则表达式

正则表达式是一类用来匹配字符串的模式,而这种模式最基本的单位是元字符。元字符是在正则表达式中具有某种特殊用途的字符,例如:.、*、?、+、()、[]等等。元字符可以代表其指定范围内的一种模式,各种功能各异的元字符通过正则表达式的规则组合在一起,可以代表几乎任何你所能想到的字符串。元字符按功能分可以分为:字符匹配元字符、次数匹配元字符、位置描定元字符、分组匹配元字符、后向引用元字符等。

不过个人认为在正则表达式中特别需要注意的一点是:1、要分清当前元字符匹配的是单个字符还是一串字符串;2、要知道当前的元字符是修饰当前匹配的字符中的哪一块,前面、后面、括号里、括号内,这一点有点类似于汉语中的主谓宾。

  在Linux中grep和egrep分别使用了基本的的正则表达式和扩展的正则表达式,区别是egrep的使用的扩展正则表多了一个+ (匹配其前面的字符至少1次) 和 | (或)以及不用加\转义。


二、grep和egrep的使用

1、grep和egrep支持的正则表达式的元字符有以下这些

(1)、针对单个字符的匹配:

 . : 匹配任意单个字符

 []: 匹配指定范围内的任意单个字符

     针对[]又有几个扩展的元字符

     [0-9]<=>[[:digit:]]:表示匹配所有数字

     [a-z]<=>[[:lower:]]:表示匹配所有小写字母

     [A-Z]<=>[[:upper:]]:表示匹配所有大写字母

             [[:alpha:]]:表示匹配所有字母

             [[:alnum:]]:表示匹配所有数字和字符

             [[:space:]]:表示匹配所有空白字符

             [[:punct:]]:表示匹配所有标点符号

[^]: 匹配指定范围外的任意单个字符


(2)、字符重复匹配:

    * : 匹配星号前面的字符任意次,*符号前面接字符,表示匹配前面那个字符零次或多次,只能匹配前面紧挨着的单个字符或分组字符

   \? : 匹配问号前面的字符0次或1次

+: 匹配其前面的字符至少1次(此为egrep或 grep -E 专有)

 \{m\}: 匹配前面的字符m次

\{m,n\}: 匹配前面的字符m至n次

\{m,\}: 匹配前面的字符至少m次,m次以上

\{0,n\}: 匹配前面的字符至多n次,0不能省略

说明:以上元字符当egrep使用时通通不用加反斜线(\)。


(3)、字符位置锚字匹配:

    ^: 用于锚定字符串的行首,匹配的字符必须是一行的第一个

    $: 用于锚定字符串的行尾,匹配的字符必须是一行的最后一个

   \<: 用于锚定词首, 用法和\b加上字符是一样的,放在字符前面

   \>: 用于锚定词尾, 用法和\b加上字符是一样的,放在字符后面


(4)、分组匹配:

  \(\):括号内的字符为一组,作为一个整体来匹配

    |: 或者(此为egrep或 grep -E 专有)

说明:小括号当egrep使用时不用加反斜线(\)。


(5)、后向引用:

\1: 这个必须和分组结合使用才能发挥作用,代表着匹配前面从左往右数第一个括号内匹配到的结果再来一遍,

注意是结果再来遍,表示前后要一模一样,数字代表着前面括号的编号,类似的可以有\2、\3...。


2、元字符总结:


基本正则表达式(grep) 基本正则表达式(egrep) 说明
字符匹配元字符 . . 匹配任意单个字符

[] [] 匹配指定范围内的任意单个字符

[^] [^] 匹配指定范围外的任意单个字符
字符重复匹配 * * 匹配星号前面的字符任意次

\? ? 匹配问号前面的字符0次或1次


+ 匹配其前面的字符至少1次

\{m\} {m} 匹配前面的字符m次

\{m,n\} {m,n} 匹配前面的字符m至n次

\{0,n\} {0,n} 匹配前面的字符至多n次
字符位置锚字匹配 ^ ^ 用于锚定字符串的行首

$ $ 用于锚定字符串的行尾

\< 或 \b \< \b 用于锚定词首

\> \b \> \b 用于锚定词尾
分组匹配 \(\) () 括号内的字符为一组
后向引用 \1 \1 表示前面从左往右数第1个括号内匹配到的结果再来一遍

\2 \2 表示前面从左往右数第2个括号内匹配到的结果再来一遍

... ...


3、用法

使用前可以先给grep定义一下别名,grep有一个参数:--color=auto,这个参数加上后可以把匹配到的结果按红色显示。。

alias grep='grep --color=auto'

grep常用参数:

-v: 取反匹配,显示不能被模式匹配到的行
-o: 显示被模式匹配到的字串,而非整行
-i: 忽略字符大小写
-E: 支持扩展的正则表达式,和egrep一样
-A: 显示被模式匹配到的行以及下面一行
-B: 显示被模式匹配到的行以及上面一行
-C: 显示被模式匹配到的行以及上下一行


(1)、匹配以Lin开头,以x结尾的字符

wKiom1MJ_mGC2AoeAACoprmcmSc969.jpg

说明:.匹配任意单个字符


(2)、匹配单词meritocratic和and之间的任意字符

wKiom1MKATbQcVvSAACajkKDvwY442.jpg

说明:\<和\>可以放在单词前后定位一个单词,.和*结合代表匹配任意字符任意次


(3)、匹配不是以点号结尾的行

在Linux中使用grep和egrep结合正则表达式查找字符_第1张图片

说明:.是元字符所以放在中括号中要使用反斜线(\)转义


(4)、匹配有四位数字的行

在Linux中使用grep和egrep结合正则表达式查找字符_第2张图片

说明:[0-9]和[[:digit:]]是一个意思表示匹配任意数字,\{4\}这个表示重复前面模式4次,所以这次有两种写法。


(5)、匹配一行以带有大写字母O且O必须在单词中间的单词开头的行

wKiom1MKBj-hCtqFAADC-Is8J1c489.jpg

说明:^代表定位到行首,\<[[:alpha:]]\{1,\}表示匹配任意字母至少一次


(6)、匹配带有一个以数字结尾的单词的行

wKioL1MKpaHRb9O1AADDWKoYR1U327.jpg

说明:首先锚定单词的首和尾,然后匹配数字前面的字母至少一次,匹配单词后面的数字一次。


(7)、匹配以标点符号结尾的行

在Linux中使用grep和egrep结合正则表达式查找字符_第3张图片

说明:[[:punct:]]$ 这么写也行,参数-v作反向匹配。


(8)、匹配一个以数字结尾的单词

wKioL1MKqeORtVUyAABao9-F7NA588.jpg

说明:参数-o可以把匹配到的结果显示,而不是整行。


(9)、匹配一个带有以hello开头并且以hello结尾的单词的行

wKioL1MKssbzrVNpAABTCbhUOxw293.jpg

说明:grep加参数-E可以使用扩展正则表达式,所以模式里的括号不用加反斜线了,把hello字符分组

     后面使用\1引用前面匹配到的结果。


(10)、|(或)的用法

wKiom1MKtGGzGZoDAABwyYKgPOI131.jpg

说明:此处使用的是egrep命令,当使用|时,放在括号里和放括号外是两回事,当不加括号时就如上

     面一样,匹配的是以小写sound开头或者带有Sound单词的行。如果要精确匹配以sound或Sound

     开头的单词时,就必须这样写了"^(sound|Sound)",如下图:

wKioL1MKtTqhJZ1vAACIFunuY2g317.jpg


(11)、最后说一个匹配IP地址的正则表达式

wKioL1MKuEmha3GGAAESmEmTOcw037.jpg

说明:IP地址的格式通常是1.0.0.1-223.255.255.254,我们可以用点号把它分成四段来写,于是就可以这

     样写第一段[0-9]匹配数字,但是每段都有一位、两位、三位数并且大于二百的数字最大是223,于

     是改进一下,可以这样写[1-9]|[1-9][0-9]|1[0-9][0-9]|2[0-2][0-3]为了让 | 自动筛选前后的结果,

     我们得给它加上括号使它成为一组,因为之前说过,加括号和不加括号是两个不同的模式,为了让

     它锚定字数字可以得到\<([1-9]|[1-9][0-9]|1[0-9]{2}|2[0-2][0-3])\>,这是第一段,然后可以

     匹配第二段的数字,第二段最大是255,于是\<([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\>

三和二是一样的,我们可以直接拿来用(\<([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\>\.){2}

第四段也是差不多的,和二、三段类似,\<([1-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\>

     把第一段后面的点号加上,和二三段组合,

     \<([1-9]|[1-9][0-9]|1[0-9]{2}|2[0-2][0-3])\>\.(\<([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\>\.){2}

     最后把四段全部结合在一起,于是我们就有了最终的结果:

\<([1-9]|[1-9][0-9]|1[0-9]{2}|2[0-2][0-3])\>\.(\<([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\>\.){2}\<([1-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\>


结语:学习是一个熟能生巧的过程,最好的办法就是学以致用。本人刚学Linux,新手一个,以上是本人的学习

     体会,不足之处还望各位大侠批评指正。