Shell脚本高级编程 二 正则表达式
2017-05-18 16:05
811 查看
在shell脚本中成功使用sed编辑器和gawk程序的关键在于熟练使用正则表达式。这能够是你,从大量数据中过滤出特定数据。
(1)什么是正则表达式
①定义
正则表达式是我们自己定义的、Linux工具用它来过滤文本的模式模板。Linux工具(比如,sed编辑器或gawk程序)能够在数据流向工具时对数据进行正则表达式模式匹配。如图所示:
例如,下面是正则表达式的一个应用,其中*是通配符:
②正则表达式的类型
使用正则表达式最大的问题在于有不止一种类型的正则表达式。Linux中的不同程序可能会用不同类型的正则表达式。这包括各种应用程序,比如编程语言(Java、Perl和Python)、Linux工具(sed编辑器、gawk程序、grep工具等),以及主流应用(如MySQL和PostgreSQL数据库服务器)。
正则表达式是用正则表达式引擎(regular expression engine)实现的,它是解释正则表达式模式并使用这些模式进行文本匹配的底层软件。
在Linux中,有两种流行的正则表达式引擎:
POSIX基本正则表达式(BRE)引擎;
POSIX扩展正则表达式(ERE)引擎。
大多数Linux工具都至少符合POSIX BRE 引擎规范,能够识别它定义的所有模式符号。但,有些工具(如sed编辑器)只实现了BRE引擎规范的子集。这是速度的要求导致的,sed编辑器希望快速地处理数据流中的文本。
POSIX BRE 引擎通常为依赖正则表达式做文本过滤的编程语言所支持。它为常见模式提供了高级模式符号和特殊符号,比如匹配数字、单词以及按字母排序的字符。gawk 程序用ERE引擎来处理它的正则表达式模式。
由于正则表达式的实现方法很多,很难用一个简洁的描述来涵盖所有可能的正则表达式。所以,这里我们只讨论最常见的正则表达式并演示如何在sed编辑器和gawk程序中使用它们。
(2)定义 BRE 模型
①纯文本
如何在sed编辑器中使用标准文本字符串来过滤数据,如例子所示:
上例子可以得出如下结论:
正则表达式不管模式在数据流中的位置和出现次数,一旦表达式匹配了文本字符串中的模式,它就会将该字符串传回Linux工具;
正则表达式模式都是区分大小写的;
正则表达式模式时部分匹配的;
正则表达式中可以使用空格和数字作为模式匹配文本,空格在整个表达式中会跟其他字符一样对待,如下例所示:
其中,第一个和第二个命令的匹配模式是一个空格;第三个命令的匹配模式是两个空格。这是用来查看文本文件中空格问题的好办法。
②特殊字符
由于我们会在正则表达式中使用文本字符,就必须注意定义文本字符时的一些特例。正则表达式识别的特殊字符包括:
.*[]^${}+?()
后续会介绍这些特殊字符在正则表达式中的作用,但现在只需记住不能在文本模式中单独使用这些字符即可。
如需使用某个特殊字符作为文本字符,需要转义。在特殊字符前添加反斜线(\),则该字符会被当做普通文本字符对待。
上例中,查找美元符号需要转义;同样查找\也需要转义。
注意,尽管斜线不是正则表达式的特殊字符,但在sed编辑器或gawk程序的正则表达式中使用会出现错误。所以,使用斜线也需要转义:
③锚字符
默认情况下,正则表达式模式匹配在数据流中任意位置的数据。有两个特殊字符可以用来将模式锁定在数据流中的行首或行尾。
锁定在行首
脱字符(caret character,^)定义从文本行的行首开始匹配。如果模式位于非行首位置,则匹配不成功。
脱字符,必须放在正则表达式中指定的模式前面:
如果脱字符放在模式中的非开头位置,它会跟普通字符一样对待:
锁定在行尾
跟行首查找相对的就是行尾查找。美元符号($)定义行尾锚点。
注意,上例中将book改为复数形式,则不能在匹配正则表达式了。因为,文本模式必须是模式要匹配的行的最后部分。
组合锚点
在一些场景下,我们需要在同一行中将行首锚点和行尾锚点组合使用。
场景一:查找含有特定文本模式的数据行,
场景二,将两个锚点直接组合在一起,中间不添加如何文本,可以过滤数据流中的空白行。如下例:
④点字符
点字符用来匹配任意的单字符,除了换行符。但点字符必须匹配一个字符,如果点字符的位置没有字符,那该模式不能被匹配。例子如下:
⑤字符组
点字符允许你匹配任意单个字符。如何只匹配给定的某些字符呢?在正则表达式中,这称为字符组(character class)。我们使用方括号([])定义字符组,在方括号中指定你要匹配的某些字符。如下例子所示:
字符组在你不确定某个字符大小写情况时,非常有用:
也可以在单个表达式中用多个字符组:
字符组中也可以使用数字:
应用场景一,检查数字是否是正确格式化了,比如电话号码和邮编。但使用时容易出错,如下例所示:
上例中,尽管我们过滤掉了过短而不可能是邮编的数字。但是超过6位的还存在,因为我们只定义了5个字符组。
要确保只匹配5位数,必须将匹配字符和其他字符分开,可以使用空格或指明它们就在行首和行尾的方法:
字符组应用场景二,解析拼写错误的单词,比如用户表单输入的数据。
本例中的两个sed打印命令利用正则表达式字符组来帮助找到文本中拼写错误的单词maintenance和separate。同样的正则表示模式也能匹配正确拼写的maintenance。
⑥排除字符组
在正则表达式中,使用脱字符(^)反转字符组的作用,即匹配不含组中字符的模式。只需要在字符组开头加个脱字符:
注意,空格也不在字符组的范围内;但即使是排除,也要求字符组必须匹配一个字符,因此at开头的行未能匹配模式。
⑦使用区间
如我们前面演示的邮编的例子,我们必须在每个字符组中列出所有可能的数字。但我们可以使用区间来代替这一方式。
区间的写法是:[第一个字符-最后一个字符]。根据Linux系统所采用的字符集,正则表达式包含这个指定区间内的任意字符。
邮编例子可改写为:
指定区间,也适用于字母:
还可以在单个字符组中指定多个不连续区间:
注意,要按字符的ASCII码中的顺序指定,比如c-a这样的指定方式是无效的。
⑧特殊字符组
除了自己定义的字符组外,BRE还包含可用来匹配特殊字符类型的特殊字符组。如下表所示:
可以在正则表达式模式中将特殊字符组像普通字符组一样使用:
⑨星号
在字符后面放置*,说明该字符将会在匹配模式中出现0次或多次:
这个模式符号应用场景,检查拼写错误或在不同语言中有拼写变种的单词。例如:
将.和*组合使用的场景,这个组合提供了匹配任意多个任意字符的模式。例如:
*还可以用在字符组上,它允许指定可能在文本中出现0次或多次的一组字符或一个字符区间:
(3)扩展正则表达式
POSIX ERE模式包括一些Linux应用和工具使用的若干额外符号。gawk程序能够识别ERE模式,但sed编辑器不能。
待补充。。。
(4)实用中的正则表达式
接下来将演示shell脚本中常见的一些正则表达式的例子。
目录文件数统计
首先,列出PATH变量中的所有目录,要意识到PATH中的每个路径都是由冒号分隔的。要获取可以在脚本中使用的目录列表,需要用空格来替换冒号。然后,使用for语句遍历每个目录中的所有文件,为每个文件将计数器+1.
验证电话号码
由gawk程序完成。待补充。。。
解析邮件地址
待补充。。。
(5)小结
(1)什么是正则表达式
①定义
正则表达式是我们自己定义的、Linux工具用它来过滤文本的模式模板。Linux工具(比如,sed编辑器或gawk程序)能够在数据流向工具时对数据进行正则表达式模式匹配。如图所示:
例如,下面是正则表达式的一个应用,其中*是通配符:
$ls -al test* -rw-rw-r-- 1 xiaoyu1 xiaoyu1 8 May 18 14:05 test -rw-rw-r-- 1 xiaoyu1 xiaoyu1 31 May 17 09:37 testfile
②正则表达式的类型
使用正则表达式最大的问题在于有不止一种类型的正则表达式。Linux中的不同程序可能会用不同类型的正则表达式。这包括各种应用程序,比如编程语言(Java、Perl和Python)、Linux工具(sed编辑器、gawk程序、grep工具等),以及主流应用(如MySQL和PostgreSQL数据库服务器)。
正则表达式是用正则表达式引擎(regular expression engine)实现的,它是解释正则表达式模式并使用这些模式进行文本匹配的底层软件。
在Linux中,有两种流行的正则表达式引擎:
POSIX基本正则表达式(BRE)引擎;
POSIX扩展正则表达式(ERE)引擎。
大多数Linux工具都至少符合POSIX BRE 引擎规范,能够识别它定义的所有模式符号。但,有些工具(如sed编辑器)只实现了BRE引擎规范的子集。这是速度的要求导致的,sed编辑器希望快速地处理数据流中的文本。
POSIX BRE 引擎通常为依赖正则表达式做文本过滤的编程语言所支持。它为常见模式提供了高级模式符号和特殊符号,比如匹配数字、单词以及按字母排序的字符。gawk 程序用ERE引擎来处理它的正则表达式模式。
由于正则表达式的实现方法很多,很难用一个简洁的描述来涵盖所有可能的正则表达式。所以,这里我们只讨论最常见的正则表达式并演示如何在sed编辑器和gawk程序中使用它们。
(2)定义 BRE 模型
①纯文本
如何在sed编辑器中使用标准文本字符串来过滤数据,如例子所示:
$echo "This is a test" | sed -n '/test/p' This is a test $echo "This is a Test" | sed -n '/test/p' $ $echo "This is a testing" | sed -n '/test/p' This is a testing
上例子可以得出如下结论:
正则表达式不管模式在数据流中的位置和出现次数,一旦表达式匹配了文本字符串中的模式,它就会将该字符串传回Linux工具;
正则表达式模式都是区分大小写的;
正则表达式模式时部分匹配的;
正则表达式中可以使用空格和数字作为模式匹配文本,空格在整个表达式中会跟其他字符一样对待,如下例所示:
$echo "This is a testing" | sed -n '/ /p' This is a testing $echo "Thisisatesting" | sed -n '/ /p' $echo "This is a testing" | sed -n '/ /p' $
其中,第一个和第二个命令的匹配模式是一个空格;第三个命令的匹配模式是两个空格。这是用来查看文本文件中空格问题的好办法。
②特殊字符
由于我们会在正则表达式中使用文本字符,就必须注意定义文本字符时的一些特例。正则表达式识别的特殊字符包括:
.*[]^${}+?()
后续会介绍这些特殊字符在正则表达式中的作用,但现在只需记住不能在文本模式中单独使用这些字符即可。
如需使用某个特殊字符作为文本字符,需要转义。在特殊字符前添加反斜线(\),则该字符会被当做普通文本字符对待。
$echo "This is a $ testing" | sed -n '/\$/p' This is a $ testing $echo "This is a $ \testing" | sed -n '/\\/p' This is a $ \testing
上例中,查找美元符号需要转义;同样查找\也需要转义。
注意,尽管斜线不是正则表达式的特殊字符,但在sed编辑器或gawk程序的正则表达式中使用会出现错误。所以,使用斜线也需要转义:
$echo "3 / 2" | sed -n '///p' sed: -e expression #1, char 3: unknown command: `/' $echo "3 / 2" | sed -n '/\//p' 3 / 2
③锚字符
默认情况下,正则表达式模式匹配在数据流中任意位置的数据。有两个特殊字符可以用来将模式锁定在数据流中的行首或行尾。
锁定在行首
脱字符(caret character,^)定义从文本行的行首开始匹配。如果模式位于非行首位置,则匹配不成功。
脱字符,必须放在正则表达式中指定的模式前面:
$echo "This is a testing" | sed -n '/^is/p' $echo "This is a testing" | sed -n '/^This/p' This is a testing
如果脱字符放在模式中的非开头位置,它会跟普通字符一样对待:
$echo "This is a^ testing" | sed -n '/a/p' This is a^ testing $echo "This is a^ testing" | sed -n '/a^/p' This is a^ testing
锁定在行尾
跟行首查找相对的就是行尾查找。美元符号($)定义行尾锚点。
$echo "This is a good book" | sed -n '/book$/p' This is a good book $echo "This book is good" | sed -n '/book$/p' $ $echo "This is a good books" | sed -n '/book$/p' $
注意,上例中将book改为复数形式,则不能在匹配正则表达式了。因为,文本模式必须是模式要匹配的行的最后部分。
组合锚点
在一些场景下,我们需要在同一行中将行首锚点和行尾锚点组合使用。
场景一:查找含有特定文本模式的数据行,
$cat data4 this is a test using... I said this is a test this is a test yes,this is a test $sed -n '/^this is a test$/p' data4 this is a test
场景二,将两个锚点直接组合在一起,中间不添加如何文本,可以过滤数据流中的空白行。如下例:
$cat data5 this is a test using... yes,this is a test $sed '/^$/d' data5 this is a test using... yes,this is a test
④点字符
点字符用来匹配任意的单字符,除了换行符。但点字符必须匹配一个字符,如果点字符的位置没有字符,那该模式不能被匹配。例子如下:
``` $cat data6 This is a test. The cat is ... That is a very nice hat. This test is at line four. at five line. $sed -n '/.at/p' data6 The cat is ... That is a very nice hat. This test is at line four. ```
⑤字符组
点字符允许你匹配任意单个字符。如何只匹配给定的某些字符呢?在正则表达式中,这称为字符组(character class)。我们使用方括号([])定义字符组,在方括号中指定你要匹配的某些字符。如下例子所示:
$sed -n '/[ch]at/p' data6 The cat is ... That is a very nice hat.
字符组在你不确定某个字符大小写情况时,非常有用:
$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
字符组中也可以使用数字:
$cat data7 line 1. hello line 2. $sed -n '/[123]/p' data7 line 1. line 2.
应用场景一,检查数字是否是正确格式化了,比如电话号码和邮编。但使用时容易出错,如下例所示:
$cat data8 60633 46201 223001 4353 22203 $sed -n ' > /[0123456789][0123456789][0123456789][0123456789][0123456789]/p > ' data8 60633 46201 223001 22203
上例中,尽管我们过滤掉了过短而不可能是邮编的数字。但是超过6位的还存在,因为我们只定义了5个字符组。
要确保只匹配5位数,必须将匹配字符和其他字符分开,可以使用空格或指明它们就在行首和行尾的方法:
$sed -n ' > /^[0123456789][0123456789][0123456789][0123456789][0123456789]$/p > ' data8 60633 46201 22203
字符组应用场景二,解析拼写错误的单词,比如用户表单输入的数据。
$sed -n ' > /maint[ea]n[ae]nce/p > /sep[ea]r[ea]te/p > ' data9 I need to maintenence done on my car. I'll paly in a seperate. After I pay for the maintenance my ...
本例中的两个sed打印命令利用正则表达式字符组来帮助找到文本中拼写错误的单词maintenance和separate。同样的正则表示模式也能匹配正确拼写的maintenance。
⑥排除字符组
在正则表达式中,使用脱字符(^)反转字符组的作用,即匹配不含组中字符的模式。只需要在字符组开头加个脱字符:
$cat data6 This is a test. The cat is ... That is a very nice hat. This test is at line four. at five line. $sed -n '/[^ch]at/p' data6 This test is at line four.
注意,空格也不在字符组的范围内;但即使是排除,也要求字符组必须匹配一个字符,因此at开头的行未能匹配模式。
⑦使用区间
如我们前面演示的邮编的例子,我们必须在每个字符组中列出所有可能的数字。但我们可以使用区间来代替这一方式。
区间的写法是:[第一个字符-最后一个字符]。根据Linux系统所采用的字符集,正则表达式包含这个指定区间内的任意字符。
邮编例子可改写为:
$sed -n '/^[0-9][0-9][0-9][0-9][0-9]$/p' data8 60633 46201 22203
指定区间,也适用于字母:
$sed -n '/[c-z]at/p' data6 The cat is ... That is a very nice hat.
还可以在单个字符组中指定多个不连续区间:
$sed -n '/[a-ch-m]at/p' data6 The cat is ... That is a very nice hat.
注意,要按字符的ASCII码中的顺序指定,比如c-a这样的指定方式是无效的。
⑧特殊字符组
除了自己定义的字符组外,BRE还包含可用来匹配特殊字符类型的特殊字符组。如下表所示:
可以在正则表达式模式中将特殊字符组像普通字符组一样使用:
$echo "aBc" | sed -n '/a[[:alpha:]]c/p' aBc $echo "abc" | sed -n '/a[[:alpha:]]c/p' abc
⑨星号
在字符后面放置*,说明该字符将会在匹配模式中出现0次或多次:
$echo "ab" | sed -n '/ae*b/p' ab $echo "aeb" | sed -n '/ae*b/p' aeb $echo "aeeeeb" | sed -n '/ae*b/p' aeeeeb
这个模式符号应用场景,检查拼写错误或在不同语言中有拼写变种的单词。例如:
$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 good student." | sed -n '/a.*student/p' This is a good student. $echo "This is a bad student." | sed -n '/a.*student/p' This is a bad student.
*还可以用在字符组上,它允许指定可能在文本中出现0次或多次的一组字符或一个字符区间:
$echo "bt" | sed -n '/b[ae]*t/p' bt $echo "bat" | sed -n '/b[ae]*t/p' bat $echo "baeaeeat" | sed -n '/b[ae]*t/p' baeaeeat
(3)扩展正则表达式
POSIX ERE模式包括一些Linux应用和工具使用的若干额外符号。gawk程序能够识别ERE模式,但sed编辑器不能。
待补充。。。
(4)实用中的正则表达式
接下来将演示shell脚本中常见的一些正则表达式的例子。
目录文件数统计
首先,列出PATH变量中的所有目录,要意识到PATH中的每个路径都是由冒号分隔的。要获取可以在脚本中使用的目录列表,需要用空格来替换冒号。然后,使用for语句遍历每个目录中的所有文件,为每个文件将计数器+1.
$cat countfiles #!/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 $./countfiles /opt/node/bin - 3 /usr/local/bin - 1 /bin - 1158 /usr/bin - 1158 /usr/local/sbin - 0 /usr/sbin - 550 /usr/local/java/jdk1.7.0_75/bin - 47 /usr/local/java/jdk1.7.0_75/jre/bin - 14 /usr/local/hadoop/bin - 11
验证电话号码
由gawk程序完成。待补充。。。
解析邮件地址
待补充。。。
(5)小结
相关文章推荐
- #7 shell脚本编程之正则表达式
- shell脚本编程(一)正则表达式
- shell脚本编程4:正则表达式
- Linux下shell脚本编程之正则表达式
- shell脚本系列-正则表达式介绍
- 【shell脚本】匹配函数的正则表达式
- Shell 常识--正则表达式,POSIX字符类以及元字符--总结自《Linux Shell 脚本攻略》
- *Linux Shell 高级编程技巧3----运行级别脚本介绍
- shell脚本学习:快速理解正则表达式之grep篇
- Shell编程之正则表达式
- Linux&shell之高级Shell脚本编程-创建函数
- shell脚本学习:正则表达式之sed,tr篇
- shell脚本知识(三) 正则表达式 grep sed awk
- 《shell 脚本攻略》--正则表达式的使用
- 高级shell脚本编程之重定向、环境变量、shell函数、echo命令用法
- 鸟哥Linux私房菜笔记(二):正则表达式、shell脚本
- shell编程学习之正则表达式
- VB脚本编程之2.0——加入正则表达式查找替换功能
- shell脚本regex正则表达式
- *Linux Shell 高级编程技巧4----几个常用的shell脚本例子