专栏首页xcywt《Linux命令行与shell脚本编程大全》第二十章 正则表达式

《Linux命令行与shell脚本编程大全》第二十章 正则表达式

20.1 什么是正则表达式

20.1.1 定义

正则表达式是你所定义的模式模板。linux工具可以用它来过滤文本。

正则表达式利用通配符来描述数据流中第一个或多个字符。

正则表达式模式含有文本或特殊字符,为sed编辑器和gawk程序定义了一个匹配数据时采用的模板。

20.1.2 正则表达式的类型

使用正则表达式最大的问题在于有不止一种类型的正则表达式。

正则表达式是通过正则表达式引擎实现的,正则表达式引擎是一套底层软件,负责解释正则表达式模式并使用这些模式进行文本匹配。

在linux中有两种流行的正则表达式引擎:

1)POSIX基础正则表达式(BRE)引擎

2)POSIX扩展正则表达式(ERE)引擎

大部分linux工具都至少符合POSIX BRE引擎规范,能够识别该规范定义的所有模式符号。

但是,有些工具只支持BRE引擎规范下的子集。比如sed,这是出于速度方面的考虑。

gawk程序用ERE引擎来处理它的正则表达式模式。

20.2 定义BRE模式

20.2.1 纯文本

例子:

$echo “This is test line” | sed -n ‘/test/p’ $echo “This is test line” | gawk ‘/test/{print $0}’

正则表达式并不关心模式在数据流中的位置,也不关心出现了多少次,只要匹配了就会将该字符串传会linux工具。

正则表达式模式区分大小写。

20.2.2 特殊字符

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

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

如果要用某个特殊字符作为文本字符,就必须转义。在前面加上反斜线\。

比如:

$echo “This cost is \$200” | sed –n ‘/\$/p’  // 注意这里应该是\$200,而不是$200

$echo “\ hahah, this is fanxiexian” | sed –n ‘/\\/p’

要使用正斜线也需要用转义字符

$ehco “6 / 3 = 2” | sed -n ‘/\//p’

20.2.3 锚字符 ^ $

默认情况下,模式出现再数据流中的任何地方,它就能匹配。

有两个特殊字符可以用来将模式锁定在数据流中的行首或行尾。

1.锁定在行首(脱字符 ^)

^ 定义从数据流中文本行的行首开始的模式。如果模式出现在行首之外的位置,正则表达式模式则无法匹配。

需要用^,就必须将它放在正则表达式中指定的模式前面。

比如:

$echo “The book store” | sed –n ‘/^book/p’  // 这样不会有输出

$echo “The book store” | sed –n ‘/^The/p’   // 这个才有

还可以输入文件:

$sed -n ‘/^this/p’ data.txt

data.txt 中以this开头的行就能找出来。

注意如果将^放到模式开头之外的其他位置,那么久跟普通字符一样了。

$echo “This is ^ test” | sed –n ‘/is ^/p’  // 匹配 is ^ 。

注意:

如果指定正则表达式模式时只用了脱字符,就不需要用反斜线来转义。

如果你在模式中先指定了脱字符,随后还有一些其他文本,那么你必须在脱字符前用转义字符。

2. 锁定在行尾

用美元符$

$echo “This is test line” | sed –n ‘/line$/p’  //这样可以匹配到

$echo “This is test lines” | sed –n ‘/line$/p’  //这样不可以匹配到

要想匹配,文本模式必须是行的最后一部分。

3. 组合锚点

比如想到匹配指定内容

$sed ‘/^this is test line$/p’ data.txt   // 匹配行 this is test line

将两个锚点直接组合在一起,之间不加任何东西,这样就过滤出数据流中的空白行。

$sed -n ‘/^$/p’ data.txt   // 这样可以把data.txt 中的空白行过滤出来。

20.2.4 点号字符 .

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

例子:

xcy@xcy-virtual-machine:~/shell/20zhang$ cat data.txt this is a test 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 xcy@xcy-virtual-machine:~/shell/20zhang$ sed -n '/.at/p'  data.txt the cat is sleeping that is a very nice hat this test is at line four xcy@xcy-virtual-machine:~/shell/20zhang$

空格也算一个字符。注意第5行没有匹配到。at前面没有字符了。

20.2.5 字符组 []

可以限定待匹配的具体字符,在正则表达式中,这称为字符组。用[]括起来

比如:

$sed –n ‘/[ch]at/p’ data.txt  // 相当于只匹配cat 或者 hat。其他的at就不匹配了。

在不确定大小写的时候,字符组会非常有用:

$echo “Yes” | sed –n ‘/[yY]es/p’

还可以用多个字符组:

$echo ‘YeS’ | sed –n ‘/[Yy][Ee][Ss]/p’

这样就相当于可以限制行的字符个数和区间了

20.2.6 排除型字符组

相当于字符组取反,可以寻找字符组中没有的字符。在前面加个脱字符就好了

$sed –n ‘/[^ch]at/p’ data.txt

匹配出c和h以外的字符。

20.2.7 区间

0 – 9,可以直接这么写[0-9] 而不需要[0123456789]

$sed –n ‘/^[0-9][0-9][0-9][0-9]&/p’ data.txt

字母也可以

$sed –n ‘/[c-h]at/p’ data.txt   // 匹配c到h这个区间的字符。

还可以指定多个不连续的区间:

$sed –n ‘/[a-ch-m]at/p’ data.txt  // 指定 a-c  和 h-m区间的字母。

$echo “This is foot” | sed –n ‘/[a-ch-n]oot/p’

20.2.8 特殊的字符组

除了自定义的区间(比如[0-9] [a-f])之外,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 “achsdsd” | sed –n ‘/[[:digit:]]/p’ $echo “2344” | sed –n ‘/[[:digit:]]/p’ $echo “achsdsd” | sed –n ‘/[[:lower:]]/p’ $echo “this is , a test” | sed –n ‘/[[:punct:]]/p’

20.2.9 星号 *

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

例子:

$echo “I am hahahaaaaa” | sed -n ‘/ha*h/p’ // 表明a可以出现0次或多次。

*还能用到字符组上,它允许指定可能在文本中出现多次的字符组或区间:

$echo ‘bt’ | sed –n ‘/b[ae]*t/p’   // a出现0次或次,e出现0次或多次

20.3 扩展正则表达式(POSIX ERE)

提供了一些可以供linux应用和工具使用的额外符号。

gawk程序(会慢一点)能够识别,sed编辑器(查找比较快)不能识别。

20.3.1 问号?

类似于星号,但是有点不同。

问号表明前面的字符可以出现0次或1次,不会匹配出现多次的字符。

$echo “bt” | gawk ‘/be?t/{print $0}’

$echo “bet” | gawk ‘/be?t/{print $0}’

$echo “beet” | gawk ‘/be?t/{print $0}’   // e 出现了2次,这里就不输出了

还可以跟字符组一起使用:

$echo “bet” | gawk ‘/b[ae]?t/{print $0}’

$echo “bat” | gawk ‘/b[ae]?t/{print $0}’

$echo “baet” | gawk ‘/b[ae]?t/{print $0}’  // 这里相当于出现了2次,也不会输出

$echo “baet” | gawk ‘/b[a-f]?t/{print $0}’

20.3.2 加号+

有点像*号。但是必须出现1次以上。可以有多次

$echo “baet” | gawk ‘/b[ae]+t/{print $0}’

20.3.3 使用花括号{}

花括号允许你为可重复的正则表达式指定一个上限,这通常称为间隔。可以用两种格式来指定区间。

1)m:正则表达式准确出现m次

2)m,n:正则表达式至少出现m次,至多n次。

注意:默认情况下gawk程序不识别正则表达式间隔。必须指定gawk程序的 –re-interval命令行选项才能识别正则表达式间隔。

例子:

$echo “bt” | gawk –re-interval ‘/be{1}t/{print $0}’  // 指定出现1次e

$echo “bet” | gawk –re-interval ‘/be{1}t/{print $0}’

$echo “beeet” | gawk –re-interval ‘/be{3,6}t/{print $0}’  // e至少出现3次,至多6次

$echo “baaeeet” | gawk –re-interval ‘/b[ae]{1,3}t/{print $0}’  // a e 出现1 -3 次

20.3.4 管道符号|

管道符号允许你在检查数据流时,用逻辑or方式指定正则表达式引擎要用的两个或多个模式。

格式如下:

expr1|expr2|……

例子:

echo "the dog is sleeping" | gawk '/cat|dog/{print $0}'  //  去匹配cat或dog

echo "the tat is sleeping" | gawk '/[ct]at|dog/{print $0}' // 去匹配 [ct]at或dog

20.3.5 表达式分组()

正则表达式模式也可以用圆括号进行分组。当你将正则表达式模式分组时,该组会被视为一个标准字符。可以像对普通字符一样给该组使用特殊字符。

例子:

$echo “Sat” | gawk ‘/Sat(urday)?/ {print $0}’

相当于把urday当做一个整体了, /SatF?/  跟这个类似,F出现0次或1次。

()需要转义的用法:

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

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

还可以将分组和管道符号一起使用来创建可能的模式匹配组:

echo "cat" | gawk '/(b|c)a(b|t)/ {print $0}'

这样相当于匹配 bab bat cab cat 四种。

20.4 正则表达式实战

20.4.1 目录文件计数

这个例子用于对PATH环境变量中各个目录里的可执行文件进行计数:

#!/bin/bash mypath=$(echo $PATH | sed 's/:/ /g')   # 这里把用冒号分割的字符串换成用空格分割 #echo "mypath = $mypath" count=0 for dir in $mypath do          check=$(ls $dir)  // 查询单个目录          for item in $check          do                    count=$[ count + 1 ]          done          echo "$dir - $count"          count=0 done

20.4.2 验证电话号码

美国的号码格式如下:

(223)456-7890

(223) 456-7890

223-456-7890

223.456.7890

最开始是( : ^\(?

三位区号(第一位必须大于2):[2-9][0-9]{2}

然后又是括号:\)?

然后是分隔符(空格,点,减号):( |-|\.)

然后是3位数字:[0-9]{3}

又是分隔符:( |-|\.)

最后四位数字:[0-9]{4}

连起来就是:

^\(?[2-9][0-9]{2}\)?( |-|\.)[0-9]{3}( |-|\.)[0-9]{4}$

例子:

xcy@xcy-virtual-machine:~/shell/20zhang$ cat isphone #!/bin/bash gawk --re-interval '/^\(?[2-9][0-9]{2}\)?( |-|\.)[0-9]{3}( |-|\.)[0-9]{4}$/ {print $0}' xcy@xcy-virtual-machine:~/shell/20zhang$ echo "222-098-2231" | ./isphone 222-098-2231 xcy@xcy-virtual-machine:~/shell/20zhang$ echo "122-098-2231" | ./isphone xcy@xcy-virtual-machine:~/shell/20zhang$ echo "222.098.2231" | ./isphone 222.098.2231 xcy@xcy-virtual-machine:~/shell/20zhang$

还可以将整个文件重定向到脚本:

phonelist里面存放着一行一行的数据:

$cat phonelist | ./isphone

这个例子其实也不是特别合理,比如下面几种情况也算是合法号码:

(235.561-4430

343) 451.4651

总之还是有待优化。

20.4.3 解析邮件地址

邮件地址的形式如下:

username@hostname

username值可用字母数字字符以及以下特殊字符:

1)点号

2)单破折线

3)加号

4)下划线

hostname部分由一个或多个域名和一个服务器名组成。只允许字母数字字符以及下面的特殊字符:比如(xiaochongyong@amwell-haha.com)

1)点号

2)下划线

username@相当于:^([a-zA-Z0-9_\-\.\+]+)@

注意: [] 里面是字符组,相当于之前的[xcs]。() 里面是表达式分组

hostname相当于:([a-zA-Z0-9_\-\.\]+)

后面还要接顶级域名。.com .cn .org  等

只能是字母字符,必须不少于两个字符,长度不超多5个字符:\.([a-zA-Z]{2,5})$

连起来就是:

^([a-zA-Z0-9_\.\-\+]+)@([a-zA-Z0-9_\.\-]+)\.([a-zA-Z]{2,5})$

例子:

xcy@xcy-virtual-machine:~/shell/20zhang$ cat isemail #!/bin/bash gawk --re-interval '/^([a-zA-Z0-9_\.\-\+]+)\@([a-zA-Z0-9_\-\.]+)\.([a-zA-Z]{2,5})$/ {print $0}' xcy@xcy-virtual-machine:~/shell/20zhang$ echo "222x2iaochongyong@s1amwell-elec.com" | ./isemail 222x2iaochongyong@s1amwell-elec.com xcy@xcy-virtual-machine:~/shell/20zhang$ echo "222x2iaocho%ngyong@s1amwell-elec.com" | ./isemail xcy@xcy-virtual-machine:~/shell/20zhang$ echo "222x2iaocho%ngyong+@s1amwell-elec.com" | ./isemail xcy@xcy-virtual-machine:~/shell/20zhang$ echo "222x2iaochongyong+@s1amwell-elec.com" | ./isemail 222x2iaochongyong+@s1amwell-elec.com xcy@xcy-virtual-machine:~/shell/20zhang$ echo "222x2iaochongyong+@s1amwell-elec..com" | ./isemail 222x2iaochongyong+@s1amwell-elec..com xcy@xcy-virtual-machine:~/shell/20zhang$ echo "222x2iaochongyong+@s1amwell-elec._.com" | ./isemail 222x2iaochongyong+@s1amwell-elec._.com xcy@xcy-virtual-machine:~/shell/20zhang$

20.5 小结

正则表达式定义了用来过滤数据流中文本的模式模板。

模式由标准文本字符和特殊字符的组成。

正则表达式引擎用特殊字符来匹配一系列单个或多个字符,这类似于其他应用程序中通配符的工作方式。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • Linux C语言高级编程之网络编程!

    简介 本章主要讲解网络编程的基础知识,主要包括七层网络模型、常用通信协议、IP地址与子网掩码及端口号、字节序。 七层网络模型 讲到网络首先说一下最常见的网络模型...

    企鹅号小编
  • Vim使用总结

    本文主要是记录使用vim过程中的一些用法,本文中介绍的命令都在vim中使用验证过。 1. 删除一行或多行 删除一行,命令格式:[:行号d] # 删除第10行 ...

    Tyan
  • 如何在 Bash 中抽取子字符串

    所谓“子字符串”就是出现在其它字符串内的字符串。 比如 “3382” 就是 “this is a 3382 test” 的子字符串。 我们有多种方法可以从中把数...

    企鹅号小编
  • Linux快捷键总结

    本文的Linux快捷键总结主要是作者使用Linux过程中常用的。 清屏,等价于clear命令 Ctrl + l 切换到命令行开始 Ctrl + a 切换到命令行...

    Tyan
  • Linux的/bin、/sbin、/usr/sbin、/usr/bin、/usr/local/bin、/usr/local/sbin

    1、Linux的/bin、/sbin、/usr/sbin、/usr/bin、/usr/local/bin、/usr/local/sbin /bin bin为...

    Tyan
  • vim note

    2016-1-22 vim plugin collections: (参考 https://www.youtube.com/watch?v=0QFR-_wUoA...

    梦里茶
  • 【Chromium中文文档】Chrome/Chromium沙箱 - 安全架构设计

    安全是Chromium最重要的目标之一。安全的关键在于理解下面这点:在我们完整地理解了系统在所有可能的输入组合下表现出的行为之后,我们才能够真的保证系统安全。对...

    梦里茶
  • Linux基础之常用命令篇

    这一篇文件主要记录了一些linux的基础命令。需要读者有linux服务器或者有mac电脑去练习。^`^. 一、命令的基本格式 [root@localhost~...

    方志朋
  • Vim 初探

    都说Vim是编辑器之神,一直也觉得vim的编码非常酷炫~ 但是作为一个编辑器之神, 却一直保持着一个非常高傲的姿态,不像打开一个记事本,一个智商正常的人瞬间就...

    IMWeb前端团队
  • 跨平台web调试代理工具--whistle

    whistle是基于Node实现的跨平台web调试代理工具,支持windows、mac、linux等所有安装了Node的操作系统,可以部署在本地机器、虚拟机或远...

    IMWeb前端团队

扫码关注云+社区

领取腾讯云代金券