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 选项与参数给大家参考
代码语言:javascript复制[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 的字符』, 例如『 aafly 』代表搜寻的字符串可以是 aay, afy, aly 即 afl 代表 a 或f 或 l 的意思! | grep -n 'gld' 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 为开头的文件,则必须要这样:
代码语言:javascript复制#以 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
- A-Z ↩
- t ↩
版权属于:龙之介大人
本文链接:https://cloud.tencent.com/developer/article/1618795
本站所有原创文章采用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可。 您可以自由的转载和修改,但请务必注明文章来源和作者署名并说明文章非原创且不可用于商业目的。