Make each program do one thing well - The Unix philosophy

image-20220506155429491

概述

原文链接

什么是正则表达式

有种标准叫做正则表示法,你可以依据该标准写出一些特殊的字符排列,叫做正则表达式

你可以利用正则表达式高效准确地匹配并处理一个或多个字符串

简言之:正则表达式就是一种处理字符串的方法

要想使用正则表达式,必须使用支持正则表达式的软件工具,比如 vim、grep、sed、awk、…

正则表达式的广泛用途

对于个人而言,使用正则表达式,能让你在使用主机时更精简高效地处理日常事务 !

比如:

当你使用编辑器之神 vim 编辑文本时,要想把「搜索/删除/替换」等动作做得漂亮,就需要配合使用正则表达式

再比如:

你的系统在繁忙时会生成成千上万行的信息,这些信息往往由极其重要的信息和无关紧要的信息杂糅(重要的信息比如:错误信息、系统被入侵的记录信息、…);要想成为一个合格的系统管理员,你就应当学会编写、学会利用正则表达式从这大量的信息中快速提取出重要信息,甚至输出生成便于查阅的报表,以此来方便自己

此外,由于正则表达式强大的字符串处理能力,有很多软件都支持正则表达式,有很多软件都使用正则表达式来实现一些功能

比如邮件服务器就使用正则表达式分析并过滤垃圾邮件

具体是怎么做的呢 ?

答:

  1. 由于垃圾邮件几乎都有标题或内容
  2. 因此,邮件服务器只需利用写好的正则表达式,就能对收到的信件的标题和内容进行字符串匹配
  3. 如此,垃圾邮件们就能被过滤出来,进而被剔除

自然这些邮件就不会被发送到用户端,既节省了用户的流量带宽,也规避了很多麻烦

啥 ?你觉得你会 ctrl+f 就够 ?

那我问你,假如你只想找到 VBird 或 Vbird 这个关键词(一个字母都不能差,大小写也不能差)

你咋办 ?

就拿被广泛使用但其实一点也不哇塞的 MS word 来举例,它并不支持正则表达式

显然,你需要分別以 VBird 和 Vbird 搜索两遍

或者你可以启用忽略大小写的功能,但这就会匹配出你不需要的关键词,比如 VBIRD、vbird、…

看吧,不支持正则表达式有时就很麻烦,但若用上正则表达式,这个需求就会和探囊取物一样简单


再举个例子

假如在系统开机的时候,总会出现一个与 mail 关键词相关的错误提示

这很令人别扭对吧 ?

你知道开机过程中的相关程序都放在 /lib/systemd/system/ 目录下,也就是说,在该目录下的某个文件中肯定有 mail 这个关键词

于是你想把这个不安分的文件“捉出来”,编辑它、修好它

你该怎么做 ?

你当然可以进入 /lib/systemd/system/ 目录,然后逐个文件地打开并搜索关键词 mail

但这个目录下很可能有大量文件 !

比如这个目录下可能会有 20 个文件,你愿意一个一个地打开搜索 ?

啥你愿意 ?你当求婚呢你愿意

假如该目录下有 100 个文件,不愿意一个一个地打开搜索了吧 ?!因为这 太 ! 慢 ! 了 !

如果你不会正则表达式,你的心情就可能是这样的

但如果你会用正则表达式,只需一行指令就找出来啦 !

1
grep 'mail' /lib/systemd/system/*

image-20220505173434394

再次强调:

只要一个软件工具支持正则表达式,那么就可以用该软件工具配合正则表达式来处理字符串

比如 vim、grep、awk、sed、… 这些软件工具,由于它们支持正则表达式,所以可以用这些软件工具配合正则表达式来处理字符串

而像 ls、cp、… 这些软件工具,由于它们不支持正则表达式,所以它们只能使用 bash 的万用字元(wildcard)

正则表达式 ≠ bash的万用字元 !这很重要 !!!

延伸型正则表达式

正则表达式分为「基础正则表达式 & 延伸型正则表达式」

对于延伸型正则表达式,除了做简单的一组字符串处理之外,还可以做群组的字符串处理

比如:当你想要搜索 VBird 或 netman 或 lman(注意是 或「OR」 而不是 和「AND」 ),你就需要使用延伸型正则表达式了

借助(|等特殊字元的帮助,就能实现这样的目的

虽然本文主要介绍基础正则表达式…

编码方式对正则表达式的影响

众所周知,计算机只能存储 0 和 1,电脑屏幕上显示的「数字、文字、…」都是由一些 0 和 1 根据某种编码方式映射转换而来

编码方式不同,正则表达式的执行结果就有可能不同

以英文大小写的编码为例,zh_TW.big5 和 C 这两种编码方式的编码顺序如下

1
2
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 也被提取了出来…

这就是不同编码方式的不同编码顺序所造成的影响

因此:

使用正则表达式时,需要特别注意当时环境的编码方式是什么,否则就可能会发现与别人不同的执行结果 !

准备工作

  1. 基于适合 POSIX 标准的编码方式
1
2
export LANG=C;
export LC_ALL=C;
  1. grep 若不带高亮,则设置高亮
1
alias grep="grep --color=auto"
  1. 下载本文练习用的文档
1
2
3
wget https://gitee.com/pj-l/static/raw/master/regular_express.txt
wget https://gitee.com/pj-l/static/raw/master/demo.sh
wget https://gitee.com/pj-l/static/raw/master/printf.txt

基础正则表达式

一些特殊符号

特殊符号 代表意义
[:digit:] 代表数字,即 0-9
[:xdigit:] 代表十六进制数字,因此包括 0-9, a-f, A-F
[:lower:] 代表小写字母,即 a-z
[:upper:] 代表大写字母,即 A-Z
[:alpha:] 代表英文大小写字母,即 A-Z, a-z
[:alnum:] 代表英文大小写字母和数字,即 A-Z, a-z, 0-9
[:blank:] 代表「空格键、Tab」
[:graph:] 代表除了「空格键、Tab」外的其它所有按键
[:space:] 代表能产生空白的字元,比如「空格键、Tab、CR、…」
[:print:] 代表任何可以被打印出来的字元
[:punct:] 代表标点符号(punctuation symbol),包括「# ‘ “ $ …」
[:cntrl:] 代表控制按键,包括「CR、LF、Tab、Del…」

一个好习惯是:用[:lower:],不用a-z,因为前者意思更明确(其它正则表达式同理)

练习笔记

如果我不想要开头是英文字母

image-20220506151220825

那个^符号,在字元集合符号[]之内与之外是不同的 ! 在[]内代表「反向选择」,在[]之外代表「定位在行首」

如果想寻找空行(hang)

image-20220506153312075

在 Linux 中,空行(hang) 就是 行(hang)首就是行(hang)尾定位符$

如果想去掉开头是#的行(hang)和空行(hang)以节省版面

image-20220506155934149

延伸型正则表达式

See here

Tools

格式化输出

printf

资料处理

倾向于整行(行)处理 => sed

倾向于一行当中分成多个栏位来处理 => awk,相当适合处理小型的资料文件,多结合 printf 进行格式化输出

档案比对

diff

cmp

patch

档案列印准备工具(给档案加标题、页码、…)

pr

(完)