Chinaunix首页 | 论坛 | 博客
  • 博客访问: 346573
  • 博文数量: 222
  • 博客积分: 9349
  • 博客等级: 中将
  • 技术积分: 2135
  • 用 户 组: 普通用户
  • 注册时间: 2010-08-07 13:45
文章分类

全部博文(222)

文章存档

2010年(222)

分类: LINUX

2010-08-18 19:03:23

附录C 正则表达式和grep

C.1.1  什么是正则表达式

正则表达式(Regular Expression)在计算机科学中,是指一个用来描述或者匹配一系列符合某个句法规则的字符串的单个字符串。在很多文本编辑器或其他工具里,正则表达式通常被用来检索和/或替换那些符合某个模式的文本内容。许多程序设计语言都支持利用正则表达式进行字符串操作。例如,在Perl中就内建了一个功能强大的正则表达式引擎。正则表达式这个概念最初是由UNIX中的工具软件(例如sed和grep)普及开的。"正则表达式"通常缩写成"regex",单数有regexp、regex,复数有regexps、regexes、regexen。

C.1.2  正则表达式历史和风格

最初的正则表达式出现于理论计算机科学的自动控制理论和形式语言理论中。在这些领域中有对计算(自动控制)的模型和对形式语言描述与分类的研究。20世纪40年代,Warren McCulloch与Walter Pitts将神经系统中的神经元描述成小而简单的自动控制元。在20世纪50年代,数学家斯蒂芬·科尔·克莱尼利用称之为正则集合的数学符号来描述此模型。肯·汤普逊将此符号系统引入编辑器QED,然后是UNIX上的编辑器ed,并最终引入grep。自此,正则表达式被广泛地使用于各种UNIX或者类似UNIX的工具,例如Perl。Perl正则表达式源自于Henry Spencer写的regex,它已经演化成了pcre(Perl兼容正则表达式Perl Compatible Regular Expressions),一个由Philip Hazel开发的,为很多现代工具所使用的库。

目前有如下两种风格的正则表达式。

POSIX风格正则表达式:Regular Expression

Perl风格正则表达式:Perl-Compatible Regular Expression

本文介绍的是POSIX风格正则表达式。

C.1.3  正则表达式文本处理工具

1.基本正则表达式(Basic Regular Expression、BRE)

grep

ed

sed

vim

emacs

2.扩展正则表达式(extended regular expression ,ERU)

egrep

awk

C.1.4  正则表达式组成

正则表达式是由普通字符(例如字符a~z)以及特殊字符(称为元字符)组成的文字模式。正则表达式作为一个模板,将某个字符模式与所搜索的字符串进行匹配。可以通过在一对分隔符之间放入表达式模式的各种组件来构造一个正则表达式,即/expression/。

正则表达式有多种不同的风格。

普通字符由所有那些未显式指定为元字符的打印和非打印字符组成。这包括所有的大写和小写字母字符、所有数字、所有标点符号及一些符号。

POSIX RE用于方括号外的元字符如表C-1所示。

特别字符

    

$

匹配输入字符串的结尾位置。如果设置了RegExp

对象的Multiline属性,则$也匹配'\n''\r'

要匹配$字符本身,请使用\$

 

标记一个子表达式的开始和结束位置。子表达式可

以获取供以后使用。要匹配这些字符,请使用\(和 \

*

匹配前面的子表达式零次或多次。要匹配 * 字符,请使用\*

+

匹配前面的子表达式一次或多次。要匹配 + 字符,请使用\+

.

匹配除换行符\n之外的任何单字符。要匹配 .,请使用 \

[

标记一个中括号表达式的开始。要匹配 [,请使用 \[

?

匹配前面的子表达式零次或一次,或指明一个非

贪婪限定符。要匹配 ? 字符,请使用 \?

\

将下一个字符标记为或特殊字符、或原义字符、

或向后引用、或八进制转义符。例如,“n”匹

配字符“n”。“\n”匹配换行符。序列“\\”匹

配“\”,而“\(”则匹配“(

^

匹配输入字符串的开始位置,除非在方括号表达式

中使用,此时它表示不接受该字符集合。要匹配 ^

字符本身,请使用 \^

{

标记限定符表达式的开始。要匹配{,请使用\{

|

指明两项之间的一个选择。要匹配|,请使用\|

POSIX RE用于方括号内的元字符,如表C-2所示。

特别字符

    

\

转义字符

^

-

用于指定字符范围

C.2  grep

C.2.1  grep简介

grep(global search regular expression(RE)是一种强大的文本搜索工具,它能使用正则表达式搜索文本,并把匹配的行打印出来。UNIX的grep家族包括grep、egrep和fgrep。egrep和fgrep的命令只跟grep有很小不同。egrep是grep的扩展,支持更多的re元字符,fgrep就是fixed grep或fast grep,它们把所有的字母都看做单词,也就是说,正则表达式中的元字符表示回其自身的字面意义,不再特殊。linux使用GNU版本的grep。它功能更强,可以通过-G、-E、-F命令行选项来使用egrep和fgrep的功能。

grep的工作方式是这样的:它在一个或多个文件中搜索字符串模板。如果模板包括空格,则必须被引用,模板后的所有字符串被看做文件名。搜索的结果被送到屏幕,不影响原文件内容。grep可用于shell脚本,因为grep通过返回一个状态值来说明搜索的状态,如果模板搜索成功,则返回0,如果搜索不成功,则返回1,如果搜索的文件不存在,则返回2。我们利用这些返回值就可进行一些自动化的文本处理工作。

C.2.2  grep家族

在grep家族中有三个实用程序:grep、egrep和fgrep。它们都用来搜索一个或多个文件,并输出一些行,这些行包含匹配正则表达式指定的规则的文本。不必是整行都匹配规则;行内的任意匹配文本是输出的充分条件。它从上到下按行检验文件的每一行。当某一行包含匹配模式时,则该行被输出。虽然这种强大功能对有意义的信息来说。可迅速减少大量的存在数据,但它不能用来只处理一部分数据。grep家族如图C-1所示。

 
(点击查看大图)图C-1  grep家族

C.2.3  grep流程

查看grep工作方式的另一方式是研究其操作流程图。图C-2中grep流程图中有两点需要注意。首先,该流程图假定未指定选项。选择一个或多个选项将改变流程图。另外虽然grep保留当前行记数,这样它就可以知道当前处理的是哪一行,但当前行编号并未在流程图中反映出来。

 
图C-1  grep流程

C.2.4  grep命令

作用:grep搜索以FILE命名的文件输入(或者是标准输入,如果没有指定文件名,或者给出的文件名是 - 的话),寻找含有与给定的模式PAT TERN相匹配的内容的行。默认情况下,grep将把含有匹配内容的行打印出来。

格式:grep [选项]... PATTERN [FILE]...

PATTERN是正则表达式书写的模式。

选项如下。

-?:同时显示匹配行上下的?行,如:grep-2patternfilename同时显示匹配行的上下两行。

-b,--byte-offset:打印匹配行前面打印该行所在的块号码。

-c,--count:只打印匹配的行数,不显示匹配的内容。

-f File,--file=File:从文件中提取模板。空文件中包含0个模板,所以什么都不匹配。

-h,--no-filename:当搜索多个文件时,不显示匹配文件名前缀。

-i,--ignore-case:忽略大小写差别。

-q,--quiet:取消显示,只返回退出状态。0则表示找到了匹配的行。

-l,--files-with-matches:打印匹配模板的文件清单。

-L,--files-without-match:打印不匹配模板的文件清单。

-n,--line-number:在匹配的行前面打印行号。

-s,--silent:不显示关于不存在或者无法读取文件的错误信息。

-v,--revert-match:反检索,只显示不匹配的行。

-w,--word-regexp:如果被\<和\>引用,就把表达式做为一个单词搜索。

-V,--version:显示软件版本信息。

几个实例如下。

要用好grep这个工具,其实就是要写好正则表达式规则,所以这里不对grep的所有功能进行实例讲解,只列几个例子:

通过管道过滤ls -l输出的内容,只显示以b开头的行:

$ ls -l | grep '^b'
显示所有以d开头的文件中包含test的行:
$ grep 'test' d*
显示在aa,bb,cc文件中匹配test的行:
$ grep 'test' aa bb cc
显示所有包含每个字符串至少有5个连续小写字符的字符串的行:
$ grep '[a-z]\{5\}' aa

C.2.5  grep应用实例

为方便说明,我们使用两个文件cwot.conf和cwot.log作为例子。cwot.conf是一个典型的服务器程序配置档,其内容为:

# CWOT Configuration File: See the cwot(8) manpage for details
# ========================== Connection =============================
# What ports, IPs and protocols we listen for
Port 1009
# Use these options to restrict which interfaces/protocols cwot will bind to
#ListenAddress 0.0.0.0
# Timeout: The number of seconds before receives and sends time out.
Timeout 300
# ============================ File =================================
# The LockFile directive sets the path to the lockfile used by cwot
# This directive should normally be left at its default value except
# the directory is NFS mounted.
LockFile /var/lock/cwot/cwot.lock
# PidFile: The file in which the server should record its process
# identification number when it starts.
PidFile /var/run/cwot.pid
cwot.log则是一个日志文件,其内容为:
1997/06/30 23:03:34 +0800 cwot: successful login f854 from f854@presenter
1997/06/30 23:30:13 +0800 cwot: fail to login jack from f891@presenter
1997/06/30 23:42:30 +0800 cwot: user f854 logout
1997/06/30 23:46:27 +0800 cwot: fail to login f823 from f823@previewer
1997/06/30 23:52:54 +0800 cwot: successful login f823 from f823@previewer
1997/06/30 23:54:34 +0800 cwot: fail to login jack from f891@presenter
1997/06/30 23:58:23 +0800 cwot: successful login fred from fred@presenter
1997/06/30 23:48:29 +0800 cwot: fail to login jack from f891@presenter
1997/06/30 23:58:48 +0800 cwot: fail to login jack from f891@presenter
1997/06/30 23:59:14 +0800 cwot: fail to login jack from f891@presenter
1997/06/30 23:59:30 +0800 cwot: user f821 logout
1997/06/30 23:59:31 +0800 cwot: successful login jack from f891@presenter
1997/06/30 23:59:50 +0800 cwot: user f826 logout

1.搜寻字串

要使用regular expression搜寻特定的英文字串,一般只列要输入要搜寻字串就可以了。例如,要在档案cwot.conf中插寻"File",可以直接使用grep -e File cwot.conf其输出结果为:

# grep -e File cwot.conf
# CWOT Configuration File: See the cwot(8) manpage for details
# ============================ File =================================
# The LockFile directive sets the path to the lockfile used by cwot
LockFile /var/lock/cwot/cwot.lock
# PidFile: The file in which the server should record its process
PidFile /var/run/cwot.pid

2.任何字符(.)

在regular expression上,点号(.)可以用来匹配任何字符。举例来说,使用命令grep f821@ cwot.log可以搜寻字符串"f821@",其输出结果为:

# grep f821@ cwot.log\
1997/06/30 23:57:14 +0800 cwot: successful login jack from f821@previewer
1997/07/01 00:00:49 +0800 cwot: successful login jack from f821@previewer
使用使用grep f82.@ cwot.log就可以搜寻"f82"和"@"之间有一字符的字符串:
# grep f82.@ cwot.log\
1997/06/30 23:46:27 +0800 cwot: fail to login f823 from f823@previewer
1997/06/30 23:52:54 +0800 cwot: successful login f823 from f823@previewer
1997/06/30 23:55:44 +0800 cwot: successful login f826 from f826@operator
1997/06/30 23:57:14 +0800 cwot: successful login jack from f821@previewer
1997/07/01 00:00:49 +0800 cwot: successful login jack from f821@previewer
1997/07/01 00:13:38 +0800 cwot: successful login f822 from f822@previewer

3.字符列举([...])

点号(.)可以用来匹配任何字符,但有些时候我们只想匹配几个特定的字符,方括号([...])就可以处理这个问题。只要把要匹配的字符放入"["和"]"之间就可以了。例如使用命令egrep f82[012]@ cwot.log,"f82[012]@"可以搜寻"f82"和"@"之间有一个"0"、"1"或"2"的字符串,其输出结果为:

# grep f82[012]@ cwot.log\
1997/06/30 23:57:14 +0800 cwot: successful login jack from f821@previewer
1997/07/01 00:00:49 +0800 cwot: successful login jack from f821@previewer
1997/07/01 00:13:38 +0800 cwot: successful login f822 from f822@previewer

4.重复任何次数(*)

星号(*)可以标示之前一个单元重复匹配的任何次数。例如命令grep f82*@ cwot.log中,"f82*@"可以搜寻"f8"和"@"之间有任何数目的"2"的输出结果为:

1997/07/01 00:13:38 +0800 cwot: successful login f822 from f822@previewer
另一例子中,命令grep '=* File' cwot.log的输出结果为:
# CWOT Configuration File: See the cwot(8) manpage for details
# ============================ File =================================


阅读(1299) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~