zoukankan      html  css  js  c++  java
  • 鸟哥的私房菜基础篇之正规表示法(Regular Expression,RE)

     

    正规表示法(Regular Expression,RE)(积极施工中)

    最近更新日期:2003/03/15

     

    正规表示法或者称为常规表示法等等,在 Unix Like 的机器当中,实在是一个相当重要的系统管理员的『利器』!此外,很多的套件也都使用正规表示法的语法在进行工作的分析用途!正规表示法最常用在字符串的搜寻与比对,他可以用来进行相当多样化的比对技巧,可以帮助套件取得所需要的资料,例如邮件服务器 sendmail 与 postfix 等,都有使用到正规表示法的方式在进行邮件的过滤工作呢!另外,正规表示法也可以帮助使用者快速取得所需要的资料,并且可以协助使用者快速的以取得的数据进行取代的动作等,鸟哥使用这个比对的技巧设计了许多管理的小程序来管理我的 Linux ,实在是相当的有用啊!注:本章节使用者需要多加练习,因为目前很多的套件都是使用正规表示法来达成其『过滤、分析』的目的,为了未来主机管理的便利性,使用者至少要能看的懂正规表示法的意义!

     
    前言
    基础正规表示法
      :grep 应用简介
      :重要特殊字符(characters)
    延伸正规表示法:
      :延伸正规表示法的特殊字符
      :egrep 应用简介
    在线文书编辑器 ed 简介
    常用的相关字符指令:
      :tr
      :col
      :expand, unexpand
      :paste, ...
    好用的搜寻软件 sed 简介
    厉害的 awk 简介
    正规表示法与管线命令之应用
    相关应用:
      :档案的比对 diff, cmp, ....
    重点回顾
    本章与 LPI 的关系
    参考资源
    本章习题练习


    前言:

    约略了解了 Linux 的基本指令 ( Shell ) 并且熟悉了 vi 之后,接下来,我们要介绍如何在文字模式底下 ( Shell 环境当中 ) 进行数据的撷取,以获得使用者所需要的重要讯息。这个功能很重要,怎么说呢?在您的计算机工作平台中,或多或少都会使用到『搜寻』以及『取代』的功能对吧!例如使用 Google 或者 Open find 去寻找网页信息、例如以文书编辑软件编辑的过程中,发现错误,而使用取代的方式来取代掉错误字眼,又例如你开启的一篇文件数据当中,由于数据量太大,所以直接以搜寻的方法去找出你所需要的关键内容等等,这些都是使用到搜寻与取代的功能喔!不过,在您惯用的操作系统当中,平常的工作下 (非服务器环境) 大概无法进行底下的功能吧:『如何在一串字符串当中,寻找有 abc 以及 tqm 还有 WWW 的关键词!』,哇!一口气要达到三组以上的关键词搜寻,大概平常的作法就是搜寻三遍吧!不过,如此一来,却又太浪费时间,并且搜寻完毕后还要将搜寻的数据结合,真麻烦!那有没有其它的方式可以达到这个目的呢?有的,那就是使用『正规表示法』来进行搜寻啰!

    • 什么是正规表示法:
      什么是正规表示式 ( Regular Expression, 底下简称 RE ) 呢?简单的说,在 Linux 的环境下,我们可以透过『字符串以及一些特殊字符的辅助』来进行文字的比对工作,好来让使用者筛选自己所需要数据。这些特殊的字符与搭配使用的工具,就构成了正规表示法的主轴啦!举个简单的例子来说,我要找到 VBird 或 Vbird 这个字样,但是不要其它的字符串,如果使用大小写都接受的情况,我就有可能会找到 VBIRD 或 vbird 或 vbIRd 等等的字眼,但是我却只要前两个字符串而已啊!这个时候,我可以使用 V[Bb]ird 来搜寻呢!呵呵!那个中括号[]就是一个很常见的表示法之一啰!此外,正规表示法搜寻的结果显示当中,由于 RE 主要针对『一行』来进行处理,如果是在文书排版的软件当中,则是以『一整段(没有断行)』来进行处理,如果该行有所需要的数据时,则取出来进行处理,如果该行无搜寻的数据,则将该行舍弃,不进行处理与显示!
       
      再举个常见的例子好了,在一堆档案当中,例如 /etc/rc.d/init.d 这个目录当中好了,如果你要找到一个档案内容含有 mail 这个字符串的文件名,要怎么搜寻呢?利用 grep 配合 mail 以及万用字符来搜寻所有的文件名『grep 'mail' /etc/rc.d/init.d/*』,赫赫!马上就可以找到你想要的档案数据啦!这样可以用来进行很快速的比对呢!对于使用纯文字文件编辑文件的人来说,真是一个好消息啊!最起码,不用像 MS word 一样,总是需要一个档案一个档案的开启啊! ^_^!说的好似很复杂,其实不怎么难的,底下我们会有很多例子让大家来实作,您就会晓得啦!
    • 正规表示法对于系统管理员的用途:
      那么为何我需要学习正规表示法呢?对于一般使用者来说,由于使用到正规表示法的机会不怎么多,因此感受不到他的魅力,不过,对于身为系统管理员的您来说,正规表示法则是一个『不可不学的好东西!』怎么说呢?由于系统如果在繁忙的情况之下,每天产生的讯息信息会多到你无法想象的地步,而我们也都知道,系统的『错误讯息登录档案』的内容(这部份我们在第五篇会详谈)记载了系统产生的所有讯息,当然,这包含你的系统是否被『入侵』的纪录数据。但是系统的数据量太大了,要系统管理员的你每天去看这么多的讯息数据,想不疯掉都很难,这个时候,我们就可以透过『正规表示法』的功能,将这些登录的信息进行处理,仅取出『错误』的信息来进行分析,哈哈!如此一来,你的系统管理工作将会『快乐得不得了』啊!当然,正规表示法的优点还不止于此,等您有一定程度的了解之后,您会爱上他喔!
    • 正规表示法的广泛用途:
      除了系统管理员之外,一大堆的软件与设定都是支持正规表示法的,最常见的例子就是『邮件服务器』啦!何解?您是否有常常收到电子邮件里最让人诟病的『广告信件』呢?那如果我在 Server 端就将广告信件给剔除的话,客户端就会减少很多不必要的频宽损耗了对吧!那么如何剔除广告信件呢?由于广告信件几乎都有一定的标题或者是内容,因此,只要每次有来信时,都先将来信的标题与内容进行特殊字符串的比对,发现有不良信件就予以剔除!嘿!这个工作怎么达到啊?就使用正规表示法啊!目前两大服务器软件 sendmail 与 postfix 都支持正规表示法的比对功能!棒的很~当然还不止于此啦,很多的服务器软件、以及套件都支持正规表示法呢!当然,虽然各家软件都支持他,不过,这些『字串』的比对还是需要系统管理员来加入比对规则的,所以啦!身为系统管理员的你,为了自身的工作以及客户端的需求,正规表示法实在是很需要学习的一项工作呢!
    • 正规表示法与 Shell 在 Linux 当中的角色定位:
      说实在的,我们在学数学的时候,一个很重要、但是粉难的东西是一定要『背』的,那就是九九表,背成功了之后,未来在数学应用的路途上,真是一帆风顺啊!这个九九表我们在小学的时候几乎背了一整年才背下来,并不是这么好背的呢!但他却是基础当中的基础!您现在一定受惠相当的多呢 ^_^!而我们谈到的这个正规表示法,与前一章的 BASH shell 就有点像是数学的九九表一样,是 Linux 基础当中的基础,虽然也是最难的部分,不过,如果学成了之后,一定是『大大的有帮助』的!不论是对于系统的认识与系统的管理部分,他都有很棒的扶助啊!所以啰,请好好的学习这个基础吧! ^_^
    • 正规表示法的严谨度:
      认知到正规表示法的重要性之后,而且也了解了 RE 的主要用途,接下来得谈一谈的是,那么正规表示法的严谨度怎么分啊?华特 ( What ) ?正规表示法还有『严谨度』之分?当然有啊!你可以使用较为松散的 RE 去找寻一篇文章的内容,也可以使用较为严谨的方式去搜寻更准确的内容 ( 有点类似 Google 里面的『模糊比对』啦! ^_^ ) 举个简单的例子来说,如果你要找寻 car 这个字眼时,那么会连 careful 也一并当作结果来输出~真是抱歉....这个时候,使用更为严谨的正规表示法,将 cat 前后的字符限制不可接受英、数字,那就可以得到更为准确的 cat 这个独立单字的字眼了!很棒不是吗!底下我们将先以较为基础的 RE 来做介绍,而后将介绍较为严谨的『延伸正规表示法』,清一清脑门,准备用功啦! ^_^

    基础正规表示法:

     


    • grep
       
      语法:

    [root @test /root ]# grep [-acinv] '搜寻字符串' filename
    参数说明:
    -a :将 binary 档案以 text 档案的方式搜寻数据
    -c :计算找到 '搜寻字符串' 的次数
    -i :忽略大小写的不同,所以大小写视为相同
    -n :顺便输出行号
    -v :反向选择,亦即显示出没有 '搜寻字符串' 内容的那一行!
    范例:
    [root @test /root]# grep 'root' /var/log/secure 
    将 /var/log/secure 这个档案中有 root 的那一行秀出来

    [root @test /root]# grep -v 'root' /var/log/secure
    若该行没有 root 才将数据秀出来到屏幕上!

    [root @test /root]# last | grep root
    若该行有 root 才将数据秀出来到屏幕上!

    [root @test /root]# grep [A-Z]ANPATH /etc/man.config
    将 /etc/man.config 这个档案当中,所有有:
    [任何一个大写字符]后面接 ANPATH 的那一行就显示出来!
    例如 AANPATH, BANPATH.... ZANPATH 等等!

    • 说明:
      grep 是一个很常见的指令,最重要的功能就是进行字符串数据的比对了,需要说明的是『grep 在一个档案中查寻一个字符串时,他是以"整行"为单位来数据的撷取的!』也就是说,假如一个档案内有 10 行,其中有两行具有你所搜寻的字符串,则将那两行显示在屏幕上,其它的就丢弃了!而 grep 除了可以进行档案的资料搜寻之外,也常常被应用在 input/output 的数据处理当中,例如常见的管线命令 ( pipe ) 就可以常常见到他的踪影!以上面的例子来看,我们可以发现前两个例子是查寻档案的内容,有没有加上 -v 所显示出来的结果是『相反的!』,而第三个例子则是以 pipe 的功能进行数据的处理的喔!至于最后一个例子比较特殊,使用到中括号 [] ,这是什么意思呢?
       
      在中括号里面『只有一个字符』,而里面的内容就是『字符的范围』啦!所以呢[A-Z]就是指:『A到Z当中的任何一个字符都能被接受,但是只有一个字符』的意思!所以,如果我想要所有的数字都接受,那就是[0-9],如果我只要接受 1,3,5 呢?就是[135]或者可以用逗号隔开[1,3,5]!所以啦,那个减号 - 在中括号当中,代表『一个范围(range)』的意思啦!中括号还有很多用途呢!底下会更详细介绍!
       
      grep 是最简单的正规表示法搜寻指令之一,他并不支持一些更严谨的正规表示法内容,不过,已经相当的好用啦!底下我们就以一个档案做为练习吧!先来查看一下这个档案内容:

    [root @test /root ]# vi regexp.txt
    This is a cat, however, I need a dog.
    I want to "Happy" and <Happy> and /Happy/ here.
    * I don't know how to do this *
    # I don't Know how to do this $
    ^ I don't KNOW how to do this @
    OK!     everythins is OK
    Now, I will eat my food
    are you         finished your work
    what do you 123 goto where
    tesaaaaatest
    quit bbbbqqa testglgs
    i will shutdown my mechine
    bye bye

    •  
      这个档案是鸟哥在 MS dos 的环境中编辑的,所以他还含有一些特殊的字符喔!使用 vi 来查看的时候还没有很清楚,如果使用 cat -A 来查看时,会出现什么呢?

    [root @test /root ]# cat -A regexp.txt
    This is a cat, however, I need a dog.^M$
    I want to "Happy" and <Happy> and /Happy/ here.^M$
    * I don't know how to do this *^M$
    # I don't Know how to do this $^M$
    ^ I don't KNOW how to do this @^M$
    OK! ^Ieverythins is OK^M$
    Now, I will eat my food^M$
    are you ^Ifinished your work^M$
    what do you 123 goto where^M$
    tesaaaaatest^M$
    quit bbbbqqa testglgs^M$
    i will shutdown my mechine^M$
    bye bye^M$

    •  
      上面粗体的地方就是 DOS 档案底下的特殊字符啦!比较一下用 vi 与 cat -A 秀出来的结果有什么不同?而主要的 DOS 字符有:
    • ^M :表示断行字符;
      ^I :表示 <tab> 造成的按键符号;
      $  :表示每一行的行尾之意!
    • 这个 regexp.txt 档案你可以在 http://linux.vbird.org/download/index.php#regular 下载回去做练习喔!好了,假设你已经将这个档案给他捉到自己的 Linux 底下了,此时,应该要来做一些小练习啰!赶紧看看吧!

    例题一:找出这个档案里面含有 know 这个字符,并将行号列出来:
    [root @test /root ]# grep -n 'know' regexp.txt
    3:* I don't know how to do this *
    grep 会一行一行的去比对 know 这个字符串,请注意,大小写是不一样的!
    当该行里面没有 know 这个字符串时, grep 就会将该行舍弃而不显示出来,
    不过,到第三行时,出现了 know 了,所以第三行就会被显示出来啦!

    例题二:找出这个档案里面含有 * 这个字符,并将行号列出来:
    [root @test /root ]# grep -n '\*' regexp.txt
    3:* I don't know how to do this *
    请特别留意喔,在正规表示法里面有相当多的『特殊字符』存在,而要
    取消掉这些特殊字符的属性时,反斜线『\』的存在就显的特别重要了!
    在这个例子中,或许你会发现使用 grep -n '*' regexp.txt 也可以得到
    相同的结果,但是,良好的习惯是需要养成的,这里,请以较为正统的
    正规表示法来去除 * 这个特殊字符的属性,对您以后一定会有很多的好处的!

    例题三:我要将所有 know 不论大小写都列出来,并列出行号:
    [root @test /root]# grep -ni 'know' regexp.txt
    3:* I don't know how to do this *
    4:# I don't Know how to do this $
    5:^ I don't KNOW how to do this @
    如果不理会大小写的差异,加入 -i 这个参数吧!列出行号就以 -n 来达成!

    •  

    • 正规表示法的特殊字符(charaters)与 egrep 指令
       
      正规表示法不止于寻找简单的字符串,他还有相当多的额外功能提供我们使用者组合、分析字符串,底下我们先来列出几个常见的正规表示法的特殊字符,搭配刚刚您下载的档案,然后再以右边的范例来实习一下吧!

    特殊字符

    表示意义与范例

    ^word

    意义:待搜寻的字符在行首
    说明:
    搜寻 word 这个字符串,『并且 word 必需为这一行的行首』。
    范例:
    找出档案中以 i 为开头的那一行,并且忽略大小写:
    [root@test root]# grep -in '^i' regexp.txt
    2:I want to "Happy" and <Happy> and /Happy/ here.
    12:i will shutdown my mechine

    word$

    意义:待搜寻的字符在行尾
    说明:
    搜寻 word 这个字符串,并且 word 必需为这一行的行尾
    范例:
    由于鸟哥提供的档案其实是 DOS 档案下的产物,所以字尾都会存在着 ^M 的字符,因此,我们先以 tr 这个指令将这个字符给他去掉,然后再找出字尾为 ye 的那一行,并显示出来!关于更多的 tr 指令的用法,我们会在后面进行说明。
    [root@test root]# cat regexp.txt|tr -d '\r' grep -n 'ye$'
    13:bye bye

    .

    意义:代表『一个』任意字符,一定要有『一个字符』存在
    说明:
    这个『.』在正规表示法当中很常用,代表的是『一个』任意字符,不是 0 个也不是多个,恰恰好就是『一个』。
    范例:
    我要将档案中有 e 与 t 并且中间含有一个字符的该行抓出来,注意喔! e 与 t 的中间一定会有一个字符存在才是成功的喔!例如下列范例:
    [root@test root]# grep -n 'e.t' regexp.txt
    7:Now, I will eat my food
    10:tesaaaaatest
    11:quit bbbbqqa testglgs

    \

    跳脱符号将特殊字符变成普通字符

    ?

    任何一个『单一』字符

    *

    随意几个任意字符

    [list]

    列表中的字符

    [range]

    列表中范围内的字符

    [^list]

    反向选择,与 [list] 相反

    [^range]

    反向选择,与 [range]相反

    \{n\}

    与前一个相同字浮连续 n 个

    \{n,m\}

    与前一个相同字浮连续 n-m 个

    •  
      请特别留意的是,『正规表示法的特殊字符』与一般在指令列输入指令的『万用字符』并不相同,例如,在万用字符当中, * 代表的是 0 ~ 无限多个字符的意思,但是在正规表示法当中, * 则是重复前一个字符的意思~使用的意义并不相同,不要搞混了!(鸟哥我一开始摸正规表示法时就很容易搞混!因为这里是新手最容易搞错的地方,特别小心啊!)

    题:我想要知道,在 /etc 底下,只要含有 XYZ 三个字符的任何一个字符的那一行就列出来,要怎样进行?
    答:

    『只要』含有 X 或 Y 或 Z 就将该行列出来,因此,我们的范围很很广啦!这个时候就必需要使用到 [] 这个咚咚!还记得中括号的用途吗?那就是『在中括号里面谨代表一个字符而已!』而这个中括号是一个『代表』,可以是一串字也可以是几个不连续的字!这里我们仅需要 XYZ 其中任何一个,所以可以这样写:
    grep [XYZ] /etc/*
    则只要在每一行当中,只要发现 X 或 Y 或 Z 任何一个,就会将他印出来!这个与 grep XYZ /etc/* 是『完全不一样』的!请仔细的思考一下ㄟ!

    •  

    例题:我想要知道在 /etc 里面,只要句首是 w-z 的就将他印出来?
    答:

    同样的,使用中括号!
    grep ^[w-z] /etc/*

    •  
      当然还有很多很多用法啦!毕竟一个正规表示法加上他附属的一些指令,几乎可以出一本书了,这里仅是想让大家了解他的好处罢了!所以就写到这里!其它的,就等着您去参详与发现啰!

    • diff
      语法:

    [root @test /root ]# diff file1 file2
    参数说明:
    范例:
    [root @test /root]# diff index.htm index.html

    说明:
    这是用来比较两个档案内容是否有不一致的指令!


    • awk
      语法:

    [root @test /root ]# last | awk '{print $1 " " $2}'
    参数说明:
    范例:
    [root @test /root]# 

    说明:
    施工中


    • sed
      语法:

    [root @test /root ]# last | sed 10,\$d 
    参数说明:
    范例:
    [root @test /root]# 

    说明:
    施工中

     


    重点回顾

    • 正规表示法 ( Regular Expression ) 的用途主要是用来做为『搜寻』字符串之用,还可以用来过滤特殊讯息等用途;
    • 由于严谨度的不同,正规表示法之上还有更严谨的延伸正规表示法;
    • 正规表示法的处理方式,经常是以『整行』或称为『整段』来进行处理的;
    • grep 与 egrep 在正规表示法里面是很常见的两支程序,其中, egrep 支持更严谨的正规表示法的语法;
    •  

    本章与 LPI 的关系


    参考资源:


  • 相关阅读:
    poj1581
    poj3094
    poj2196
    poj1003
    poj2262
    poj1083
    poj3299
    poj2739
    poj1552
    js 获取元素高度和宽度
  • 原文地址:https://www.cnblogs.com/datalife/p/2001469.html
Copyright © 2011-2022 走看看