龙之介大人

linux的正则表达式
9.1 正则表达式的介绍正则表达式 (Regular Expression, RE, 或称为常规表示法)是透过一些...
扫描右侧二维码阅读全文
22
2019/08

linux的正则表达式

9.1 正则表达式的介绍

正则表达式 (Regular Expression, RE, 或称为常规表示法)是透过一些特殊字符的排列,用以搜寻/取代/删除一列或多列 文字字符串,简单的说,正则表达式就是用在字符串的处理上面的一项『表示式』。正则表达式并不是一个工具程序,而是一个字符串处理的标准依据,如果您想要以正则表达式的方式处理字符串,就得要使用支持正则表达式的工具程序 才行,这类的工具程序很多,例如 vi, sed, awk 等等。

正则表达式对于系统管理员来说实在是很重要!因为系统会产生很多的讯息,这些讯息有的重要有的仅是告知, 此时,管理员可以透过正则表达式的功能来将重要讯息撷取出来,并产生便于查阅的报表来简化管理流程。此外,很多的软件包也都支持正则表达式的分析,例如邮件服务器的过滤机制(过滤垃圾信件)就是很重要的一个例子。 所以,您最好要了解正则表达式的相关技能,在未来管理主机时,才能够更精简处理您的日常事务!

9.2 什么是正则表达式

约略了解了 Linux 的基本指令 (BASH) 并且熟悉了 vim 之后,相信你对于敲击键盘的打字与指令下 达比较不陌生了吧?接下来,底下要开始介绍一个很重要的观念,那就是所谓的『正则表达式 (Regular Expression)』!

  • 什么是正则表达式

任何一个有经验的系统管理员,都会告诉你:『正则表达式真是挺重要的!』 为什么很重要呢? 因为日常生活就使用的到啊!举个例子来说, 在你日常使用 vim 作字处理或程序撰写时使用到的 『搜寻/取代』等等的功能, 这些举动要作的漂亮,就得要配合正则表达式来处理!

简单的说,正则表达式就是处理字符串的方法,他是以行为单位来进行字符串的处理行为, 正规 表示法透过一些特殊符号的辅助,可以让使用者轻易的达到『搜寻/删除/取代』某特定字符串的处 理程序!
  • 举例来说:

我只想找到 VBird(前面两个大写字符) 或 Vbird(仅有一个大写字符) 这个字样,但是不要其他的字符串 (例如 VBIRD, vbird 等不需要),该如何办理?如果在没有正则表达式的环境中(例如 MS word),你或许就得要使用忽略大小写的办法,或者是分别以 VBird 及 Vbird 搜寻两遍。但是,忽略大小写可能会搜寻到 VBIRD/vbird/VbIrD 等等的不需要的字符串而造成困扰。

  • 再举个系统常见的例子

假设妳发现系统在开机的时候,老是会出现一个关于 mail 程序的错误,而开机过程的相关程序都是在 /lib/systemd/system/ 底下,也就是说,在该目录底下的某个文件内具有 mail 这个关键词,你想要将该文件捉出来进行查询修改的动作。此时你怎么找出来含有 这个关键词的文件? 你当然可以一个文件一个文件的开启,然后去搜寻 mail 这个关键词,只是..... 该目录底下的文件可能不止 100 个~ 如果了解正则表达式的相关技巧,那么只要一行指令就找出来啦:grep 'mail' /lib/systemd/system/* 那个 grep 就是支持正则表达式的工具程序之一!

谈到这里就得要进一步说明了,正则表达式基本上是一种『表示法』, 只要工具程序支持这种表示法,那么该工具程序就可以用来作为正则表达式的字符串处理之用。 例如 vi, grep, awk ,sed 等 等工具,因为她们有支持正则表达式, 所以,这些工具就可以使用正则表达式的特殊字符来进行字符串的处理。但例如 cp, ls 等指令并未支持正则表达式, 所以就只能使用 bash 自己本身的通配符而已。

9.2.1 正则表达式对于系统管理员的用途

那么为何我需要学习正则表达式呢?对于一般使用者来说,由于使用到正则表达式的机会可能不怎么多, 因此感受不到他的魅力,不过,对于身为系统管理员的你来说,正则表达式则是一个『不可不学的好东西!』怎么说呢?由于系统如果在繁忙的情况之下,每天产生的讯息信息会多到你无法想象的地步,而我们也都知道,系统的『错误讯息登录文件』 的内容记载了系统产生的所有讯息,当然,这包含你的系统是否被『入侵』的记录数据。

但是系统的数据量太大了,要身为系统管理员的你每天去看这么多的讯息数据, 从千百行的资料 里面找出一行有问题的讯息,光是用肉眼去看,想不疯掉都很难! 这个时候,我们就可以使用正则表达式的功能,将这些登录的信息进行处理, 仅取出有问题的信息来进行分析,当然,正则表达式的优点还不止于此!

9.2.2 正则表达式的广泛用途

正则表达式除了可以让系统管理员管理主机更为便利之外,事实上,由于正则表达式强大的字符串处理能力,目前一堆软件都支持正则表达式呢!最常见的就是『邮件服务器』!

如果你留意互联网上的消息,那么应该不难发现,目前造成网络大塞车的主因之一就是垃圾/广告信件了, 而如果我们可以在服务器端,就将这些问题邮件剔除的话,客户端就会减少很多不必要的带宽耗损了。 那么如何剔除广告信件呢?由于广告信件几乎都有一定的标题或者是内容,因此,只要每次有来信时,都先将来信的标题与内容进行特殊字符串的比对,发现有不良信件就 予以剔除!这个工作怎么达到啊?就使用正则表达式啊!目前两大邮件服务器软件 sendmail 与 postfix 以及支持邮件服务器的相关分析软件,都支持正则表达式的比对功能!

当然,虽然各家软件都支持他,不过,这些『字符串』的比对还是需要系统管理员来加入比对规则的,所以啦!身为系统管理员的你,为了自身的工作以及客户端的需求,正则表达式实在是很需要也很值得学习的一项工具!

9.3 基础正则表达式

既然正则表达式是处理字符串的一种表示方式,那么对字符排序有影响的语系数据就会对正则表达式的结果有影响! 此外,正则表达式也需要支持工具程序来辅助才行!所以,我们这里就先介绍一个最简单的字符串撷取功能的工具程序,那就是 grep.前一章已经介绍过 grep 的相关选项与参数,本章着重在较进阶的 grep 选项说明!

9.3.1 语系对正则表达式的影响

为什么语系的数据会影响到正则表达式的输出结果呢?由于不同语系的编码数据并不相同,所以就会造成数据撷取结果的差异了。

举例来说,在英文大小写的编码顺序中,zh_TW.big5 及 C 这两种语系的输出结果分别如下:

  • LANG=C 时:0 1 2 3 4 ... A B C D ... Z a b c d ...z
  • LANG=zh_TW 时:0 1 2 3 4 ... a A b B c C d D ... z Z

上面的顺序是编码的顺序,我们可以很清楚的发现这两种语系明显就是不一样!如果你想要撷取大写 字符而使用 [A-Z] 时,会发现 LANG=C 确实可以仅捉到大写字符(因为是连续的),但是如果 LANG=zh_TW.big5 时,就会发现到,连同小写的 b-z 也会被撷取出来!

所以,使用正则表达式时,需要特别留意当时环境的语系为何,否则可能会发现不相同的撷取结果

由于一般我们在练习正则表达式时,使用的是兼容于 POSIX 的标准,因此就使用『 C 』这个语系

另外,为了要避免这样编码所造成的英文与数字的撷取问题,因此有些特殊的符号我们得要了解一下的! 这些符号主要有底下这些意义:

特殊符号代表意义
[:alnum:]代表英文大小写字符及数字,亦即 0-9, A-Z, a-z
[:alpha:]代表任何英文大小写字符,亦即 A-Z, a-z
[:blank:]代表空格键与 [Tab] 按键两者
[:cntrl:]代表键盘上面的控制按键,亦即包括 CR, LF, Tab, Del.. 等等
[:digit:]代表数字而已,亦即 0-9
[:graph:]除了空格符 (空格键与 [Tab] 按键) 外的其他所有按键
[:lower:]代表小写字符,亦即 a-z
[:print:]代表任何可以被打印出来的字符
[:punct:]代表标点符号 (punctuation symbol),亦即:" ' ? ! ; : # $...
[:upper:]代表大写字符,亦即 A-Z
[:space:]任何会产生空白的字符,包括空格键, [Tab], CR 等等
[:xdigit:]代表 16 进位的数字类型,因此包括: 0-9, A-F, a-f 的数字与字符

尤其上表中的[:alnum:], [:alpha:], [:upper:], [:lower:], [:digit:] 这几个一定要知道代表什么意思,因为他要比 a-z 或 A-Z 的用途要确定的很!

9.4 grep 的一些进阶选项

在上一章BASH里面的 grep 谈论过一些基础用法,但其实 grep 还有不少的进阶用法!底下我们仅列出较进阶的 grep 选项与参数给大家参考

[dmtsai@study ~]$ grep [-A] [-B] [--color=auto] '搜寻字符串' filename 
选项与参数:
-A :后面可加数字,为 after 的意思,除了列出该行外,后续的 n 行也列出来; 
-B :后面可加数字,为 befer 的意思,除了列出该行外,前面的 n 行也列出来; 
--color=auto 可将正确的那个撷取数据列出颜色


#范例一:用 dmesg 列出核心讯息,再以 grep 找出内含 drm 那行
[root@study tmp]# dmesg | grep 'drm'
[    1.226571] [drm] Initialized drm 1.1.0 20060810
[    1.263043] [drm] DMA map mode: Using physical TTM page addresses.
[    1.263133] [drm] Capabilities:
[    1.263134] [drm]   Rect copy.
#dmesg 可列出核心产生的讯息!包括硬件侦测的流程也会显示出来。


#范例二:承上题,要将捉到的关键词显色,且加上行号来表示:
[root@study tmp]# dmesg | grep -n --color=auto 'drm'
1239:[    1.226571] [drm] Initialized drm 1.1.0 20060810
1265:[    1.263043] [drm] DMA map mode: Using physical TTM page addresses.
1266:[    1.263133] [drm] Capabilities:
1267:[    1.263134] [drm]   Rect copy.
1268:[    1.263135] [drm]   Cursor.
1269:[    1.263135] [drm]   Cursor bypass.
#除了 drm 会有特殊颜色来表示之外,最前面还有行号喔!其实颜色显示已经是默认在 alias 当中了!


范例三:承上题,在关键词所在行的前两行与后三行也一起捉出来显示
[root@study tmp]# dmesg  | grep -n -A3 -B2 'drm'
#你会发现关键词之前与之后的数行也被显示出来!这样可以让你将关键词前后数据捉出来进行分析!

grep 是一个很常见也很常用的指令,他最重要的功能就是进行字符串数据的比对,然后将符合用户需求的字符串打印出来。 需要说明的是grep 在数据中查寻一个字符串时,是以 "整行" 为单位来 进行数据的撷取的!也就是说,假如一个文件内有 10 行,其中有两行具有你所搜寻的字符串,则将那两行显示在屏幕上,其他的就丢弃了!

9.5 基础正则表达式字符汇整

RE 字符意义范例题正则
^word意义:待搜寻的字符串(word)在行首!搜寻行首为 # 开始的那一行,并列出行号grep -n '^#' regular_express.txt
word$意义:待搜寻的字符串(word)在行尾!范例:将行尾为 ! 的那一行打印出来,并列出行号grep -n '!$' regular_express.txt
.意义:代表『一定有一个任意字符』的字符!范例:搜寻的字符串可以是 (eve) (eae) (eee) (e e), 但不能仅有 (ee) !亦即 e 与 e 中间『一定』仅有一个字符,而空格符也是字符!grep -n 'e.e' regular_express.txt
\意义:转义字符,将特殊符号的特殊意义去除!范例:搜寻含有单引号 ' 的那一行!grep -n ' regular_express.txt
*意义:重复零个到无穷多个的前一个 RE 字符范例:找出含有 (es) (ess) (esss) 等等的字符串,注意,因为 可以是 0 个,所以 es 也 是符合带搜寻字符串。另外,因为 为重复『前一个 RE 字符』的符号,因此,在 之前必须要紧接着一个 RE 字符喔!例如任意字符则为 『.*』 !grep -n 'ess*' regular_express.txt
[list]意义:字符集合的 RE 字符,里面列出想要撷取的字符!范例:搜寻含有 (gl) 或 (gd) 的那一行,需要特别留意的是,在 [] 当中『谨代表一个待搜寻 [list] 的字符』, 例如『 a[afl]y 』代表搜寻的字符串可以是 aay, afy, aly 即 [afl] 代表 a 或f 或 l 的意思!grep -n 'g[ld]' regular_express.txt
[n1-n2]意义:字符集合的 RE 字符,里面列出想要撷取的字符范围!范例:搜寻含有任意数字的那一行!需特别留意,在字符集合 [] 中的减号 - 是有特殊意义的,他代表两个字符之间的所有连续字符!但这个连续与否与 ASCII 编码有关,因此,你的编码需要设定正确(在 bash 当中,需要确定 LANG 与 LANGUAGE 的变量是否正确!) 例如所有大写字符则为 [A-Z]grep -n '[A-Z]' regular_express.txt
[^list]意义:字符集合的 RE 字符,里面列出不要的字符串或范围!范例:搜寻的字符串可以是 (oog) (ood) 但不能是 (oot) ,那个 ^ 在 [] 内时,代表的意义是『反向选择』的意思。 例如,我不要大写字符,则为 1。但是,需要特别注意的是, 如果以 grep -n 1 regular_express.txt 来搜寻,却发现该文件内的所有行都被列出,为什么?因为这个 1 是『非大写字符』的意思,因为每一行均有非大写字符,例如第一行的 "Open Source" 就有 p,e,n,o.... 等等的小写字grep -n 'oo2' regular_express.txt
{n,m}意义:连续 n 到 m 个的『前一个 RE 字符』意义:若为 {n} 则是连续 n 个的前一个 RE 字符,意义:若是 {n,} 则是连续 n 个以上的前一个 RE 字符! 范例:在 g 与 g 之间有 2 个到3 个的 o 存在的字符串,亦即 (goog)(gooog) grep -n 'go{2,3}g' regular_express.txt
  • 『正则表达式的特殊字符』与一般在指令列输入指令的『通配符』并不相同

例如,在 通配符当中的 代表的是『 0 ~ 无限多个字符』的意思,但是在正则表达式当中, 则是『重复 0 到无穷多个的前一个 RE 字符』的意思.

举例来说,不支持正则表达式的 ls 这个工具中,若我们使用 『ls -l 』 代表的是任意档名的文件, 而 『ls -l a 』代表的是以 a 为开头的任何档名的文件,但在正则表达式中,我们要找到含有以 a 为开头的文件,则必须要这样:

#以 ls -l 配合 grep 找出 /etc/ 底下文件类型为链接文件属性的文件名
[root@study /]# ls -l | grep '^l'
lrwxrwxrwx.   1 root root    7 8月   9 03:42 bin -> usr/bin
lrwxrwxrwx.   1 root root    7 8月   9 03:42 lib -> usr/lib
lrwxrwxrwx.   1 root root    9 8月   9 03:42 lib64 -> usr/lib64
#由于 ls -l 列出连结档时标头会是『 lrwxrwxrwx 』,因此使用如上的指令即可找出结果

#若仅想要列出几个文件,再以『 |wc -l 』 来累加处理即可。
[root@study /]# ls -l | grep '^l' | wc -l
4

  1. A-Z
  2. t
最后修改:2019 年 08 月 22 日 11 : 31 PM

发表评论