一、 定义

正则表达式是你所定义的模式模板 (pattern template),利用通配符来描述数据流中的一个或多个字符。Linux工具(比如sed或gawk)能够在处理数据时用它对数据进行模式匹配。如果数据匹配模式,它就会被接受并进一步处理;否则,它就会被滤掉。

二、 正则表达式的类型

使用正则表达式最大的问题在于有不止一种类型的正则表达式。Linux中的不同应用程序可能会用不同类型的正则表达式。这其中包括编程语言(Java、 Perl和Python)、 Linux实用工具(sed、gawk、grep)以及主流应用(MySQL、PostgreSQL)。

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

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

  • POSIX基础正则表达式(basic regular expression, BRE)引擎
  • POSIX扩展正则表达式(extended regular expression, ERE)引擎

多数Linux工具都至少符合BRE引擎规范,能够识别该规范定义的所有模式符号。遗憾的是,有些工具(比如sed)只符合了BRE引擎规范的子集。这是出于速度方面的考虑导致的,因为sed希望能尽可能快地处理数据流中的文本。gawk程序则用ERE引擎来处理它的正则表达式模式。

三、 定义 BRE 模式

最基本的BRE模式是匹配数据流中的文本字符。

1. 纯文本

如何在sed编辑器和gawk程序中用标准文本字符串来过滤数据。

$ echo "This is a test" | sed -n '/test/p'
This is a test
$ echo "This is a test" | sed -n '/trial/p'
$
$ echo "This is a test" | gawk '/test/{print $0}'
This is a test
$ echo "This is a test" | gawk '/trial/{print $0}'
$

正则表达式并不关心模式在数据流中的位置,它也不关心模式出现了多少次。一旦匹配了文本字符串中任意位置上的模式,它就会将该字符串传回Linux工具。

正则表达式对匹配的模式非常挑剔。第一条原则就是:正则表达式模式都区分大小写。

$ echo "This is a test" | sed -n '/this/p'
$
$ echo "This is a test" | sed -n '/This/p'
This is a test

在正则表达式中,你不用写出整个单词。只要定义的文本出现在数据流中,正则表达式就能够匹配。

$ echo "The books are expensive" | sed -n '/book/p'
The books are expensive#也可以在正则表达式中使用空格和数字。
$ echo "This is line number 1" | sed -n '/ber 1/p'
This is line number 1

甚至可以创建匹配多个连续空格的正则表达式模式。

$ cat data1
This is a normal line of text.
This is a  line with too many spaces.$ sed -n '/  /p' data1
This is a  line with too many spaces.

2. 特殊字符与转义

正则表达式识别的特殊字符包括:.*[]^${}\+?|()。如果要用某个特殊字符作为文本字符,就必须转义,转义字符默认是反斜线 \。

举个例子,如果要查找文本中的美元符,只要在它前面加个反斜线。

$ cat data2
The cost is $4.00$ sed -n '/\$/p' data2
The cost is $4.00

由于反斜线是特殊字符,如果要在正则表达式模式中使用它,你必须对其转义,这样就产生了两个反斜线。

echo "\ is a special character" | sed -n '/\\/p'
\ is a special character

尽管正斜线不是正则表达式的特殊字符,但如果它出现在sed或gawk程序的正则表达式中,你就会得到一个错误。

$ echo "3 / 2" | sed -n '///p'
sed: -e expression #1, char 2: No previous regular expression

要使用正斜线,也需要进行转义。

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

3. 锚字符

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

1)锁定在行首

脱字符(^)定义从数据流中文本行的行首开始的模式。如果模式出现在行首之外的位置,正则表达式模式则无法匹配。要用脱字符,就必须将它放在正则表达式中指定的模式前面。

$ echo "The book store" | sed -n '/^book/p'
$
$ echo "Books are great" | sed -n '/^Book/p'
Books are great

如果你将脱字符放到模式开头之外的其他位置,那么它就跟不再是特殊字符了:

$ echo "This ^ is a test" | sed -n '/s ^/p'
This ^ is a test

2)锁定在行尾

$ 定义了行尾锚点,将其放在文本模式之后来指明数据行必须以该文本模式结尾。

$ echo "This is a good book" | sed -n '/book$/p'
This is a good book$ echo "This book is good" | sed -n '/book$/p'
$

3)组合锚点

在一些常见情况下,可以在同一行中将行首锚点和行尾锚点组合在一起使用。

  • 第一种情况,查找只含有特定文本模式的数据行。
cat data4
this is a test of using both anchors
I said this is a test
this is a test
I'm sure this is a test.$ sed -n '/^this is a test$/p' data4
this is a test
  • 第二种情况,将两个锚点直接组合在一起,之间不加任何文本。这样可以过滤出数据流中的空白行,还可以再用d命令删除空白行。
$ 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.

4. 点号字符

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

$ 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.

第四行能匹配是因为在正则表达式中,空格也是字符,因此at前面的空格刚好匹配了该模式。第五行证明了这点,将at放在行首就不会匹配该模式了。

5. 字符组

字符组(character class)可以定义用来匹配文本模式中某个位置的一组字符。如果字符组中的某个字符出现在了数据流中,那它就匹配了该模式。使用方括号来定义一个字符组,方括号中包含所有你希望出现在该字符组中的字符。然后你可以在模式中使用整个组,就跟使用其他通配符一样。

在不太确定某个字符的大小写时,字符组会非常有用。

$ echo "Yes" | sed -n '/[Yy]es/p'
Yes
$ echo "yes" | sed -n '/[Yy]es/p'
yes

可以在单个表达式中用多个字符组。

$ echo "Yes" | sed -n '/[Yy][Ee][Ss]/p'
Yes
$ echo "yEs" | sed -n '/[Yy][Ee][Ss]/p'
yEs
$ echo "yeS" | sed -n '/[Yy][Ee][Ss]/p'
yeS

字符组不必只含有字母,也可以在其中使用数字。

$ 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.

6. 排除型字符组

在字符组的开头加脱字符(^),可以寻找组中没有的字符,相当于非操作。

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

通过排除型字符组,正则表达式模式会匹配c或h之外的任何字符以及文本模式。由于空格字符属于这个范围,它通过了模式匹配。即使是排除,字符组仍然必须匹配一个字符,所以以at开头的行仍然未能匹配模式。

7. 区间

在每个字符组中列出所有可能的数字,这实在有点麻烦,可以用单破折线符号在字符组中表示字符区间。只需要指定区间的第一个字符、单破折线以及区间的最后一个字符就行了。

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.

该字符组允许区间a~c、 h~m中的字母出现在at文本前,但不允许出现d~g的字母。

$ echo "I'm getting too fat." | sed -n '/[a-ch-m]at/p'
$

该模式不匹配fat文本,因为它没在指定的区间。

8. 特殊的字符组

BRE还包含了一些特殊的字符组,可用来匹配特定类型的字符。

可以在正则表达式模式中将特殊字符组像普通字符组一样使用。

$ 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
$ echo "This is a test" | sed -n '/[[:punct:]]/p'
$

9. 星号

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

$ echo "ik" | sed -n '/ie*k/p'
ik
$ echo "iek" | sed -n '/ie*k/p'
iek
$ echo "ieeeek" | sed -n '/ie*k/p'
ieeeek

这个模式符号广泛用于处理有常见拼写错误或在不同语言中有拼写变化的单词。举个例子,如果需要写个可能用在美式或英式英语中的脚本,可以这么写:

$ echo "I'm getting a color TV" | sed -n '/colou*r/p'
I'm getting a color TV
$ echo "I'm getting a colour TV" | sed -n '/colou*r/p'
I'm getting a colour TV

另一个方便的特性是将.和*组合起来,这个组合能够匹配任意数量的任意字符。它通常用在数据流中两个可能相邻或不相邻的文本字符串之间。

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

星号还能用在字符组上。它允许指定可能在文本中出现多次的字符组或字符区间。

$ echo "bt" | sed -n '/b[ae]*t/p'
bt
$ echo "bat" | sed -n '/b[ae]*t/p'
bat
$ echo "btt" | sed -n '/b[ae]*t/p'
btt
$ echo "baat" | sed -n '/b[ae]*t/p'
baat
$ echo "baaeeet" | sed -n '/b[ae]*t/p'
baaeeet
$ echo "baakeeet" | sed -n '/b[ae]*t/p'
$

三、 扩展正则表达式

POSIX ERE模式包括了一些可供Linux应用和工具使用的额外符号。 gawk程序能够识别ERE模式,但sed编辑器不能。

1. 问号

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

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

与星号一样,你可以将问号和字符组一起使用。

$ echo "bt" | gawk '/b[ae]?t/{print $0}'
bt
$ echo "bat" | gawk '/b[ae]?t/{print $0}'
bat
$ echo "bot" | gawk '/b[ae]?t/{print $0}'
$
$ echo "bet" | gawk '/b[ae]?t/{print $0}'
bet
$ echo "baet" | gawk '/b[ae]?t/{print $0}'
$

2. 加号

加号也类似于星号,加号表明前面的字符可以出现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}'
$

3. 使用花括号

{}允许你为可重复的正则表达式指定一个上限,这通常称为间隔(interval),这可以精确调整字符或字符集在模式中具体出现的次数。

可以用两种格式来指定区间:

  • m:正则表达式准确出现m次。
  • m,n:正则表达式至少出现m次,至多n次。

gawk默认不会识别正则表达式间隔,必须指定gawk的--re- interval 选项才能识别正则表达式间隔。

通过指定间隔为1,限定了该字符在匹配模式的字符串中出现的次数。如果该字符出现多次,模式匹配就不成立。

$ 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}'
$

很多时候,同时指定下限和上限也很方便。

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

间隔模式匹配同样适用于字符组。

$ echo "bt" | gawk --re-interval '/b[ae]{1,2}t/{print $0}'
$
$ echo "bat" | gawk --re-interval '/b[ae]{1,2}t/{print $0}'
bat
$ echo "bet" | gawk --re-interval '/b[ae]{1,2}t/{print $0}'
bet
$ echo "beat" | gawk --re-interval '/b[ae]{1,2}t/{print $0}'
beat

4. 管道符号

| 代表以逻辑OR方式指定正则表达式引擎要用的两个或多个模式。

$ 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}'
$

正则表达式和管道符号之间不能有空格,否则它们也会被认为是正则表达式模式的一部分。管道符号两侧可以采用任何正则表达式模式来定义文本。

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

5. 表达式分组

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

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

将分组和管道符号一起使用来创建可能的模式匹配组是很常见的做法。

$ 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}'
$

四、 正则表达式实战

1. 目录文件计数

我们先看一个shell脚本,它会对PATH环境变量中定义的目录里的可执行文件进行计数。

首先你得将PATH变量解析成单独的目录名。

echo $PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games

PATH中的每个路径由冒号分隔,要获取可在脚本中使用的目录列表,就必须用空格来替换冒号。

$ echo $PATH | sed 's/:/ /g'
/usr/local/sbin /usr/local/bin /usr/sbin /usr/bin /sbin /bin /usr/games /usr/local/games

分离出目录之后,你就可以使用标准for语句中来遍历每个目录。

mypath=$(echo $PATH | sed 's/:/ /g')
for directory in $mypath
do
...
done

一旦获得了单个目录,就可以用ls命令来列出每个目录中的文件,并用另一个for语句来遍历每个文件,为文件计数器增值。

#!/bin/bash
# count number of files in your PATH
mypath=$(echo $PATH | sed 's/:/ /g')
count=0
for directory in $mypath
do
check=$(ls $directory)
for item in $check
do
count=$[ $count + 1 ]
done
echo "$directory - $count"
count=0
done

有另一个思路,只用一个循环,ll 每个目录|wc –l,然后减1。要减1是因为ll最后会输出一个total 文件总大小,会导致比实际文件数多一行,需要去掉。

#!/bin/bash
mypath=$(echo $PATH | sed 's/:/ /g')
count=0for directory in $mypath
do
rows=$(ls -l $directory/|wc -l) #注意$directory后一定要有/
count=$[$rows - 1]
echo "$directory - $count" #ls -l会输出多一行total,需要去掉
count=0
rows=0
done

由于/root/bin目录不存在,会变为0-1=-1,当然你可以先判断目录是不是存在再计数。

2. 验证电话号码

正则表达式通常用于验证数据,确保脚本中数据格式的正确性。

一个常见的数据验证应用就是检查电话号码。数据输入表单通常会要求填入电话号码,而用户输入格式错误的电话号码是常有的事。在美国,电话号码有几种常见的形式:

(123)456-7890
(123) 456-7890
123-456-7890
123.456.7890

这样用户在表单中输入的电话号码就有4种可能,正则表达式必须足够强大,才能处理每一种情况。

在构建正则表达式时,最好从左手边开始,然后构建用来匹配可能遇到的字符的模式。

在这个例子中,电话号码中可能有也可能没有左圆括号。这可以用如下模式来匹配:

^\(?

紧接着就是3位区号。在美国,区号以数字2开始(没有以数字0或1开始的区号),最大可到9。

# 第一个字符是2~9的数字,后跟任意两位数字
[2-9][0-9]{2}

在区号后面,收尾的右圆括号可能存在,也可能不存在。

\)?

在区号后,存在如下可能:有一个空格,没有空格,有一条单破折线或一个点。你可以对它们使用管道符号,并用圆括号进行分组。你必须将点字符转义,否则它会被解释成可匹配任意字符。

(| |-|\.)

紧接着是3位电话交换机号码。这里没什么需要特别注意的。

[0-9]{3}

在电话交换机号码之后,你必须匹配一个空格、一条单破折线或一个点

( |-|\.)

最后,必须在字符串尾部匹配4位本地电话分机号。

[0-9]{4}$

完整的模式如下:

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

在gawk程序中使用正则表达式间隔时,必须使用--re-interval命令行选项,否则就没法得到正确的结果。

cat phonelist
000-000-0000
123-456-7890
212-555-1234
(317)555-1234
(202) 555-9876
33523
1234567890
234.123.4567
$ cat isphone
#!/bin/bash
# script to filter out bad phone numbers
gawk --re-interval '/^\(?[2-9][0-9]{2}\)?(| |-|\¬
[0-9]{3}( |-|\.)[0-9]{4}/{print $0}'$ cat phonelist | ./isphone
212-555-1234
(317)555-1234
(202) 555-9876
234.123.4567

shell脚本编程笔记(十)—— 正则表达式相关推荐

  1. shell脚本编程笔记(二)—— 执行数学运算

    数学运算在编程中也很重要,shell对它的支持并不算好,本文整理一下shell进行数学运算的途径,各种方法的缺点. 一. expr命令 shell最开始处理数学表达式的命令,可以在命令行做算术运算,参 ...

  2. shell脚本编程笔记(十二)—— gawk程序

    一. 简介 虽然sed是非常方便自动修改文本文件的工具,但其也有自身的限制.通常你需要一个用来处理文件中的数据的更高级工具,它能提供一个类编程环境来修改和重新组织文件中的数据,这正是gawk能够做到的 ...

  3. 个人整理shell脚本编程笔记

    一.脚本格式 vim shell.sh #!/bin/bash //声明脚本解释器,这个'#'号不是注释,其余是注释 #Program: //程序内容说明 #History: //时间和作者 二.sh ...

  4. shell脚本编程笔记(九)—— 初识流编辑器 sed

    一. 流编辑器 sed编辑器被称作流编辑器(stream editor).在交互式文本编辑器中(比如vim),你可以用键盘命令来交互式地插入.删除或替换数据中的文本.流编辑器则基于预先提供的一组命令来 ...

  5. linux shell脚本编程笔记(三): 三种引号的区别

    双引号.单引号.反引号的区别 测试用例: OPDATE=`date -d '-1 day' +%Y%m%d` for i in $(seq 10) do FILEDATE=`date -d " ...

  6. shell脚本编程学习笔记5(xdl)——正则表达式

    shell脚本编程学习笔记5--正则表达式 1,简介 正则表达式,用来在文件中匹配符合条件的字符串,包含匹配.注意是文件中选择字符串,和通配符是 不同的.grep,awk,sed等命令可以支持正则表达 ...

  7. 《Linux命令行与shell脚本编程大全》(第三版)读书笔记

    第一部分 Linux命令行 第三章.基本的bash shell命令 bash手册 man 命令 例子: man cat 空格翻页.回车下一行.左右键看右侧(左侧)内容.q退出 info info in ...

  8. linux脚本求命令行上整数和,《Linux命令行与shell脚本编程大全》 第二十二章 学习札记...

    <Linux命令行与shell脚本编程大全> 第二十二章 学习笔记 第二十二章:使用其他shell 什么是dash shell Debian的dash shell是ash shell的直系 ...

  9. shell脚本编程学习笔记2(xdl)——Bash变量

    shell脚本编程学习笔记2--Bash变量 1,变量简介 1,计算机内存单元2,设置规则字母数组下划线组成,不能以数字开头Bash中,默认类型字符串型,变量类型可修改 2,Bash变量规则 1,变量 ...

最新文章

  1. Script:收集11g Oracle实例IO性能信息
  2. 情怀java手机网游_经典端游移植手游 “情怀”赋予老IP全新活力
  3. ITK:在没有写访问权的情况下迭代图像中的区域
  4. DBUtils连接池,websocket
  5. 小白学Linux(一:开门见山)
  6. 互联网日报 | 3月20日 星期六 | 荣耀CEO赵明谈发展目标;家乐福中国未来谋求独立上市;微盟开放接入支付宝小程序能力...
  7. 前端笔记 | CSS进阶
  8. 微信支付v3 php 源码,求微信支付wxpayv3服务端完整代码
  9. SpringBoot中的约定优于配置
  10. linux下载win软件,Linux大神都知道的下载工具,其实Windows平台也能用
  11. 黄山旅游自助攻略住宿行程路线篇
  12. 基于VUE技术的超市购物系统设计答辩PPT模板
  13. Unity场景优化工具:Mesh Baker 基础教程(贴图篇)
  14. 华为智慧屏鸿蒙20,华为智慧屏SE系列首销 搭载鸿蒙分布式跨屏技术
  15. MySQL inet aton函数,基于Mysql的IP处理函数inet_aton()与inet_ntoa()的深入分析
  16. MySQL DELETE 操作后没有释放磁盘空间
  17. 教师网络计算机研修日志,网络研修日志范文(通用7篇)
  18. 场景化分析rem布局原理
  19. 【转】Android开发工具--android-studio-bundle-141.2288178
  20. 数据恢复(Data recovery)

热门文章

  1. 解决hotmail邮箱无法登陆问题
  2. 邓宁-克鲁格效应(Dunning-Kruger effect,达克效应)
  3. C#圆通快递电子面单api接口调用方法
  4. 加mp4文件后js失效_video不能播放mp4的问题(一)
  5. progress的高级过程调用以及全局变量
  6. Android相机预览设置适配及显示方式
  7. tomcat7绿色版服务配置
  8. 了解JavaScript的Flow、认识Flow及其简单用法
  9. 优秀网页翻译:高精度 10MHz GPS 驯服钟 (GPSDO) - Part 5
  10. php 获取扩展模块信息,查看PHP opcode扩展模块及Web服务