正则表达式

1、前情提要

  以前我们用grep在一个文件中找出包含某些字符串的行,比如在头文件中找出一个宏定义。其实grep还可以找出符合某个模式(Pattern)的一类字符串。例如找出所有符合xxxxx@xxxx.xxx模式的字符串(也就是email地址),要求x字符可以是字母、数字、下划线、小数点或减号,email地址的每一部分可以有一个或多个x字符,例如abc.d@ef.com、1_2@987-6.54,当然符合这个模式的不全是合法的email地址,但至少可以做一次初步筛选,筛掉a.b、c@d等肯定不是email地址的字符串。再比如,找出所有符合yyy.yyy.yyy.yyy模式的字符串(也就是IP地址),要求y是0-9的数字,IP地址的每一部分可以有1-3个y字符。

如果要用grep查找一个模式,如何表示这个模式,这一类字符串,而不是一个特定的字符串呢?从这两个简单的例子可以看出,要表示一个模式至少应该包含以下信息:

  字符类(Character Class):如上例的x和y,它们在模式中表示一个字符,但是取值范围是一类字符中的任意一个。

  数量限定符(Quantifier): 邮件地址的每一部分可以有一个或多个x字符,IP地址的每一部分可以有1-3个y字符

各种字符类以及普通字符之间的位置关系:例如邮件地址分三部分,用普通字符@和.隔开,IP地址分四部分,用.隔开,每一部分都可以用字符类和数量限定符描述。

为了表示位置关系,还有位置限定符(Anchor)的概念,将在下面介绍。

规定一些特殊语法表示字符类、数量限定符和位置关系,然后用这些特殊语法和普通字符一起表示一个模式,这就是正则表达式(Regular Expression)。

例如email地址的正则表达式可以写成[a-zA-Z0-9_.-]+@[a-zA-Z0-9_.-]+.[a-zA-Z0-9_.-]+,IP地址的正则表达式可以写成[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}。

等下介绍正则表达式的语法,我们先看看正则表达式在grep中怎么用。例如有这样一个文本文件testgrep:

[root@VM_0_5_centos test]# vi testgrep.file
[root@VM_0_5_centos test]# cat testgrep.file
192.168.13.108
123.5254.045.678
abcde52s
198.23.233.342
1233.232.232.4

查找其中包含IP地址的行:

注:1、egrep相当于grep -E,表示采用Extended正则表达式语法。另外还有fgrep命令,相当于grep -F,表示只搜索固定字符串而不搜索正则表达式模式,不会按正则表达式的语法解释后面的参数。

2、正则表达式参数用单引号括起来了,因为正则表达式中用到的很多特殊字符在Shell中也有特殊含义(例如\),只有用单引号括起来才能保证这些字符原封不动地传给grep命令,而不会被Shell解释掉。

grep的正则表达式有Basic和Extended两种规范:
1、grep正则表达式的Extended规范在基本语法中介绍;
2、Basic规范也有Extended规范的这些语法,只是字符?+{}|()应解释为普通字符,要表示上述特殊含义则需要加\转义。如果用grep而不是egrep,并且不加-E参数,则应该遵照Basic规范来写正则表达式。

问:192.168.13.108符合上述模式,由三个.隔开的四段组成,每段都是1到3个数字,所以这一行被找出来了,可为什么1233.232.232.4也被找出来了呢?

答:因为grep找的是包含某一模式的行,这一行包含一个符合模式的字符串233.232.232.4。相反,123.5254.045.678这一行不包含符合模式的字符串,所以不会被找出来。

  grep是一种查找过滤工具,正则表达式在grep中用来查找符合模式的字符串。其实正则表达式还有一个重要的应用是验证用户输入是否合法,例如用户通过网页表单提交自己的email地址,就需要用程序验证一下是不是合法的email地址,这个工作可以在网页的Javascript中做,也可以在网站后台的程序中做,例如PHP、Perl、Python、Ruby、Java或C,所有这些语言都支持正则表达式,可以说,目前不支持正则表达式的编程语言实在很少见。除了编程语言之外,很多UNIX命令和工具也都支持正则表达式,例如grep、vi、sed、awk、emacs等等。“正则表达式”就像“变量”一样,它是一个广泛的概念,而不是某一种工具或编程语言的特性。

2、基本语法

  我们知道C的变量和Shell脚本变量的定义和使用方法很不相同,表达能力也不相同,C的变量有各种类型,而Shell脚本变量都是字符串。同样道理,各种工具和编程语言所使用的正则表达式规范的语法并不相同,表达能力也各不相同,有的正则表达式规范引入很多扩展,能表达更复杂的模式,但各种正则表达式规范的基本概念都是相通的。本节介绍egrep(1)所使用的正则表达式,它大致上符合POSIX正则表达式规范,详见regex(7)(看这个man page对你的英文绝对是很好的锻炼)。希望读者仿照上一节的例子,一边学习语法,一边用egrep命令做实验。

字符类:

字符 含义 举例
. 匹配任意一个字符  abc.可以匹配abcd、abc9等
[] 匹配括号中的任意一个字符 [abc]d可以匹配ad、bd或cd
- 在[]括号内表示字符范围  [0-9a-fA-F]可以匹配一位十六进制数字
^ 位于[]括号内的开头,匹配除括号中的字符之外的任意一个字符  [^xy]匹配除xy之外的任一字符,因此[^xy]1可以匹配a1、b1但不匹配x1、y1
[[:xxx:]] grep工具预定义的一些命名字符类  [[:alpha:]]匹配一个字母,[[:digit:]]匹配一个数字

数量限定符:

字符 含义 举例
?
紧跟在它前面的单元应匹配零次或一次
[0-9]?\.[0-9]匹配0.0、2.3、.5等,由于.在正则表达式中是一个特殊字符,所以需要用\转义一下,取字面值
+
紧跟在它前面的单元应匹配一次或多次   
[a-zA-Z0-9_.-]+@[a-zA-Z0-9_.-]+\.[a-zA-Z0-9_.-]+匹配email地址
*
紧跟在它前面的单元应匹配零次或多次
[0-9][0-9]*匹配至少一位数字,等价于[0-9]+,[a-zA-Z_]+[a-zA-Z_0-9]*匹配C语言的标识符
{N}
紧跟在它前面的单元应精确匹配N次  
[1-9][0-9]{2}匹配从100到999的整数
{n,}
紧跟在它前面的单元应匹配至少N次   
[1-9][0-9]{2,}匹配三位以上(含三位)的整数
{,M}
紧跟在它前面的单元应匹配最多M次 
[0-9]{,1}相当于[0-9]?
{N,M}
紧跟在它前面的单元应匹配至少N次,最多M次  
[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}匹配IP地址

再次注意grep找的是包含某一模式的行,而不是完全匹配某一模式的行。再举个例子,如果文本文件的内容是:

[root@VM_0_5_centos test]# vi testfile.txt
[root@VM_0_5_centos test]# cat testfile.txt
acaabc
caad
efg
sdcasd
sda

查找a*这个模式的结果是三行都被找出来了:

注:a匹配0个或多个a,而第三行包含0个a,所以也包含了这一模式。单独用a这样的正则表达式做查找没什么意义,一般是把a*作为正则表达式的一部分来用。

位置限定符:

字符 含义 举例
^
匹配行首的位置
^Content匹配位于一行开头的Content
$
匹配行末的位置       
 ;$匹配位于一行结尾的;号,^$匹配空行
\<
匹配单词开头的位置  
\<th匹配... this,但不匹配ethernet、tenth
\>
匹配单词结尾的位置    
p\>匹配leap ...,但不匹配parent、sleepy
\b
匹配单词开头或结尾的位置     
\bat\b匹配... at ...,但不匹配cat、atexit、batch
\B
匹配非单词开头和结尾的位置  
 \Bat\B匹配battery,但不匹配... attend、hat ...

位置限定符可以帮助grep更准确地查找,例如上一节我们用[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}查找IP地址,找到这两行:

192.168.13.108
198.23.233.342
1233.232.232.4

如果用^[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}$查找,就可以把1233.232.232.4这一行过滤掉了。

其它特殊字符:

字符 含义 举例
\
转义字符,普通字符转义为特殊字符,特殊字符转义为普通字符 
普通字符<写成\<表示单词开头的位置,特殊字符.写成\.以及\写成\\就当作普通字符来匹配
()
 将正则表达式的一部分括起来组成一个单元,可以对整个单元使用数量限定符
([0-9]{1,3}\.){3}[0-9]{1,3}匹配IP地址
|
 连接两个子表达式,表示或的关系
n(o|either)匹配no或neither

以上介绍的是grep正则表达式的Extended规范,Basic规范也有这些语法,只是字符?+{}|()应解释为普通字符,要表示上述特殊含义则需要加\转义。如果用grep而不是egrep,并且不加-E参数,则应该遵照Basic规范来写正则表达式。

3、grep

1.作用

Linux系统中grep命令是一种强大的文本搜索工具,它能使用正则表达式搜索文本,并把匹 配的行打印出来。grep全称是Global Regular Expression Print,表示全局正则表达式版本,它的使用权限是所有用户。

rep家族包括grep、egrep和fgrep:
egrep和fgrep的命令只跟grep有很小不同。
egrep是grep的扩展,支持更多的re元字符;
fgrep就是fixed grep或fast grep,它们把所有的字母都看作单词,也就是说,正则表达式中的元字符表示回其自身的字面意义,不再特殊。
linux使用GNU版本的grep。它功能更强,可以通过-G、-E、-F命令行选项来使用egrep和fgrep的功能。

2.格式

grep [options]

3.主要参数

grep --help

[options]主要参数:
-c:只输出匹配行的计数。
-i:不区分大小写。
-h:查询多文件时不显示文件名。
-l:查询多文件时只输出包含匹配字符的文件名。
-n:显示匹配行及行号。
-s:不显示不存在或无匹配文本的错误信息。
-v:显示不包含匹配文本的所有行。
--color=auto :可以将找到的关键词部分加上颜色的显示。

pattern正则表达式主要参数:(pattern部分最好用双引号)

\      忽略正则表达式中特殊字符的原有含义。
^    匹配正则表达式的开始行。
$    匹配正则表达式的结束行。
\<    从匹配正则表达 式的行开始。
\>    到匹配正则表达式的行结束。
[ ] 单个字符,如[A]即A符合要求 。
[ - ] 范围,如[A-Z],即A、B、C一直到Z都符合要求 。
.    所有的单个字符。
*    有字符,长度可以为0。

4.grep命令使用简单实例

显示所有以d开头的文件中包含 test的行;
[root@VM_0_5_centos test]# grep “test” d* 显示在aa,bb,cc文件中匹配test的行(./*表示当前目录下的所有文件);
[root@VM_0_5_centos test]# grep ‘test’ aa bb cc
[root@VM_0_5_centos test]# egrep "sda" ./*
./test:sda
./testfile.txt:sda
./testsd:sdadf
[root@VM_0_5_centos test]# egrep "sda" ./* -n
./test:2:sda
./testfile.txt:5:sda
./testsd:2:sdadf
[root@VM_0_5_centos test]# egrep "sda" ./* -c
./test:1
./testfile.txt:1
./testgrep.file:0
./testsd:1
./tfun.sh:0 显示所有包含每个字符串至少有5个连续小写字符的字符串的行;
[root@VM_0_5_centos test]# grep “[a-z]\{5\}” test
[root@VM_0_5_centos test]# egrep “[a-z]{5}” test
如果asd被匹配,则s就被存储到内存中,并标记为1,然后搜索任意个字符(.*),这些字符后面紧跟着另外一个s(\1),找到就显示该行。如果用egrep或grep -E,就不用”\”号进行转义,直接写成’a(s)d.*\1′就可以了;
[root@VM_0_5_centos test]# grep “a\(s\)d.*\1” test

5.grep命令使用复杂实例

明确要求搜索子目录:

grep -r

或忽略子目录:

grep -d skip

如果有很多输出时,您可以通过管道将其转到’less’上阅读:

IP地址的正则表达式可以写成[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}。
grep -E '^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$' testgrep.file | less

这样,您就可以更方便地阅读。

注意:您必需提供一个文件过滤方式(搜索全部文件的话用 *)。如果您忘了,’grep’会一直等着,直到该程序被中断。如果您遇到了这样的情况,按 ,然后再试。

下面还有一些有意思的命令行参数:

grep -i pattern files  //不区分大小写地搜索。默认情况区分大小写,
grep -l pattern files //只列出匹配的文件名,
grep -L pattern files //列出不匹配的文件名,
grep -w pattern files //只匹配整个单词,而不是字符串的一部分(如匹配’magic’,而不是’magical’),
grep -C number pattern files//匹配的上下文分别显示[number]行,
grep pattern1 | pattern2 files //显示匹配 pattern1 或 pattern2 的行,
例如:
grep "abc\|xyz" testfile 表示过滤包含abc或xyz的行
grep pattern1 files | grep pattern2 //显示既匹配 pattern1 又匹配 pattern2 的行。
grep -n pattern files //即可显示行号信息
grep -c pattern files //即可查找总行数

这里还有些用于搜索的特殊符号:

\< 和 \>     分别标注单词的开始与结尾
例如:
grep man * 会匹配 ‘Batman’、’manic’、’man’等;
grep ‘\<man’ * 会匹配’manic’和’man’,但不是’Batman’;
grep ‘\<man\>’ 只匹配’man’,而不是’Batman’或’manic’等其他的字符串。
‘^’ 指匹配的字符串在行首;
‘$’ 指匹配的字符串在行尾;
例如:
[root@VM_0_5_centos test]# cat testfile.txt
acaabc
caad
efg
sdcasd
sda
[root@VM_0_5_centos test]# grep '^a' testfile.txt
acaabc
[root@VM_0_5_centos test]# grep -E '^a' testfile.txt
acaabc
[root@VM_0_5_centos test]# grep -E 'a$' testfile.txt
sda

shell编程基础(五): 正则表达式及其使用的更多相关文章

  1. shell编程基础(转载)

    Shell编程基础 原作者 Leal:请参阅页面底部的编者列表. 授权许可: 创作共享署名协议 GNU 自由文档许可证 注意:本文仍然在持续的修订之中,且错漏之处可能较多.如果能够阅读英语的话,可以考 ...

  2. 7-1 shell编程基础之二

    shell编程基础之二 算数运算 bash中的算术运算:help let +, -, *, /, %取模(取余), **(乘方),乘法符号有些场景中需要转义 实现算术运算: (1) let var=算 ...

  3. 【转】Shell编程基础篇-下

    [转]Shell编程基础篇-下 1.1 条件表达式 1.1.1 文件判断 常用文件测试操作符 常用文件测试操作符 说明 -d文件,d的全拼为directory 文件存在且为目录则为真,即测试表达式成立 ...

  4. 【转】Shell编程基础篇-上

    [转]Shell编程基础篇-上 1.1 前言 1.1.1 为什么学Shell Shell脚本语言是实现Linux/UNIX系统管理及自动化运维所必备的重要工具, Linux/UNIX系统的底层及基础应 ...

  5. 【Shell 编程基础第二部分】Shell里的流程控制、Shell里的函数及脚本调试方法!

    http://blog.csdn.net/xiaominghimi/article/details/7603003 本站文章均为李华明Himi原创,转载务必在明显处注明:转载自[黑米GameDev街区 ...

  6. Linux学习之二十一-shell编程基础

    Shell编程基础 Shell 是一个用 C 语言编写的程序,它是用户使用 Linux 的桥梁.Shell 既是一种命令语言,又是一种程序设计语言.Shell 是指一种应用程序,这个应用程序提供了一个 ...

  7. 6-2 shell编程基础

    shell编程基础 编程基础 Linus:Talk is cheap, show me the code 程序和编程风格 程序: 程序:算法+数据结构 数据:是程序的核心 算法:处理数据的方式 数据结 ...

  8. Linux(五)shell编程基础

    一.Linux shell简介 1.shell概述 Shell 是用户与内核进行交互操作的一种接口,目前最流行的 Shell 称为 bash Shell          Shell 是一门编程语言& ...

  9. 基于Linux系统的Shell编程-基础篇

    1. Shell基础介绍 1.1 Shell编程的意义 为什么使用shell编程 节约时间 1.2 显示脚本执行过程 前面有+表示执行过的命令的 前面没有东西,表示输出到屏幕上的内容. [root@C ...

随机推荐

  1. 与http协作的web服务器--代理、网关、隧道

    一台服务器可以搭建多个web站点 代理: 接受客户端发送的请求,转发给其他服务器,然后接受服务器的返回结果(响应)再返回给客户端.每次经过代理服务器,就会追加写入via首部信息. 按两种基准分类.一种 ...

  2. hbase删除table时,显示table不存在

    hbase删除table时,显示table不存在,但是创建table时,显示table存在. 解决方案: 清空zookeeper数据.(重新安装zookeeper)

  3. 网络操作系统 第七章 管理TCP/IP网络

    本章小结 本章介绍了TCP/IP的相关概念,并且在此处基础上,介绍了Windows Server 2008中使用TCP/IP网络配置工具实现网络连接和管理的方法,在Linux系统中,讲解了是如何使用图 ...

  4. homekit2mqtt on DietPi

    Followed official install instruction and got: dns_sd.DNSServiceRegister(self.serviceRef, flags, ifa ...

  5. 自定义Token的CAS登录

    工作中实际遇到的需求,我们有一个旧系统,用了CAS的单点登录,现在有一个外部系统,准备从它那里单点进来,这个外部系统提供了一个token参数来标记这是哪一个用户,我们用他们提供的方式解析出对应的用户, ...

  6. 安装PyQt5时缺少designer.exe的解决办法

    学习PyQt框架的时候,看到了可以用可视化的方法搭建界面,好像ios的xib,但是安装完成pyqt5后怎么都找不designer.exe这个文件,于是查到了一下.发现了可以通过安装pip instal ...

  7. 在MFC中支持sqlite3

    在vc环境下支持sqlite3的方法有很多,sqlite官网也有推荐sqlitewrappers列表,我选用的是CppSqlite 建立MFC工程的步骤我就不赘述了,以下操作均假设你已经创建好了一个M ...

  8. C#基础笔记

    第一章: 1.C#创建程序的基本结构 class 类名 { static void Main(string[]args) { } } 注意:1)namespace2)using3)类名命名规则:字母. ...

  9. 为什么要学习 Spring Boot?

    我们知道,从 2002 年开始,Spring 一直在飞速的发展,如今已经成为了在Java EE(Java Enterprise Edition)开发中真正意义上的标准,但是随着技术的发展,Java E ...

  10. Javascript高级编程学习笔记(17)—— 引用类型(6)基本包装类

    基本包装类 基本包装类这个概念或许有的小伙伴没有听说过 但是小伙伴们有没有想过,为什么基本数据类型的实例也有方法呢? 其实这些方法都来自基本包装类型 这是JS为了方便操作基础数据类型而创建的特殊引用类 ...