【12.1.1】什么是正则表达式?
1)简单说:正则表示法就是处理字串的方法,他是以行为单位来进行字串的处理行为, 正则表达式透过一些特殊符号的辅助,可以让使用者轻易的达到查找、删除、替换某特定字串的处理程序!
【12.1.5】扩展的正则表达式
正则表达式的字串表示方式依照不同的严谨度而分为: 基础正则表达式与扩展正则表达式。
【12.2】基础正则表达式
【12.2.1】语系对正则表达式的影响
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
2)为了要避免这样编码所造成的英文与数字的撷取问题,因此有些特殊的符号我们得要了解一下的! 这些符号主要有底下这些意义:
(1)
【12.2.2】grep的一些高级参数
(2)
【荔枝】
(3)
补充1:grep 是一个很常见也很常用的命令,他最重要的功能就是进行字串数据的比对,然后将符合使用者需求的字串列印出来。 需要说明的是 grep 在数据中查寻一个字串时,是以 "整行" 为单位来进行数据的撷取的!
补充2:你可以在 ~/.bashrc 内加上这行:『alias grep='grep --color=auto'』再以『 source ~/.bashrc 』来立即生效即可喔! 这样每次运行 grep 他都会自动帮你加上颜色显示啦!
(4)
(5)
【12.2.3】基础正则表达式练习
1)底下的练习大前提是:
● 语系已经使用『 export LANG=C 』的配置值;
● grep 已经使用 alias 配置成为『 grep --color=auto 』
2)regular_express.txt 内容如下:
"Open Source" is a good mechanism to develop programs.
apple is my favorite food.
Football game is not use feet only.
this dress doesn't fit me.
However, this dress is about $ 3183 dollars.
GNU is free air not free beer.
Her hair is very beauty.
I can't finish the test.
Oh! The soup taste good.
motorcycle is cheap than car.
This window is clear.
the symbol '*' is represented as start.
Oh! My god!
The gd software is a library for drafting programs.
You are the best is mean you are the no. 1.
The world is the same with "glad".
I like dog.
google is the best tools for search keyword.
goooooogle yes!
go! go! Let's go.
# I am VBird
【荔枝1】在文件中搜索the这个字符串所在的数据行;
(6)
【荔枝2】反向选择;
(7)
(8)
【荔枝】 利用中括号 [] 来搜索集合字节
(9)
(10)
(11)
【继续荔枝】假设我 oo 前面不想要有小写字节,所以,我可以这样写 [^abcd....z]oo , 但是这样似乎不怎么方便,由於小写字节的 ASCII 上编码的顺序是连续的, 因此,我们可以将之简化为底下这样:
(12)
(13)
(14)
(15)
【荔枝3】行首与行尾字符 ^$
(16)
(17)
(18)
(19)
【注意】^ 在中括号[] 外面表示行首,在中括号里面表示取反或非;
(20)
【注意】
注意1:上荔枝中 用 反斜杠 \ 对 点符号. 进行了转义;
注意2:你或许会觉得奇怪,但是第 5~9 行最后面也是 . 啊~怎么无法列印出来? 这里就牵涉到 Windows 平台的软件对於断行字节的判断问题了!我们使用 cat -A 将第五行拿出来看, 你会发现:
(21)
在上面的表格中我们可以发现 5~9 行为 Windows 的断行字节 (^M$) ,而正常的 Linux 应该仅有第 10 行显示的那样 ($) 。所以罗,那个 . 自然就不是紧接在 $ 之前喔!也就捉不到 5~9 行了!
(22)
(23)
【荔枝4】任意一个字节. 与重复字节*
这两个符号在正规表示法的意义如下:
● . (小数点):代表『一定有一个任意字节』的意思;
● * (星星号):代表『重复前一个字节, 0 到无穷多次』的意思,为组合形态
场景1)假设我需要找出 g??d 的字串,亦即共有四个字节, 起头是 g 而结束是 d ,我可以这样做:
(24)
补充1)因为 * 代表的是『重复 0 个或多个前面的 RE 字符』的意义, 因此,『o*』代表的是:『拥有空字节或一个 o 以上的字节』, 特别注意,因为允许空字节(就是有没有字节都可以的意思),因此,『 grep -n 'o*' regular_express.txt 』将会把所有的数据都列印出来萤幕上!
补充2)那如果是『oo*』呢?则第一个 o 肯定必须要存在,第二个 o 则是可有可无的多个 o , 所以,凡是含有 o, oo, ooo, oooo 等等,都可以被列出来~
补充3)同理,当我们需要『至少两个 o 以上的字串』时,就需要 ooo* ,亦即是:
(25)
(26)
(27)
(28)
【荔枝5】限定连续 正则表达式 字符范围 {}
在上个例题当中,我们可以利用 . 与 RE 字符及 * 来配置 0 个到无限多个重复字节, 那如果我想要限制一个范围区间内的重复字节数呢?举例来说,我想要找出两个到五个 o 的连续字串,该如何作?这时候就得要使用到限定范围的字符 {} 了。 但因为 { 与 } 的符号在 shell 是有特殊意义的,因此, 我们必须要使用跳脱字符 \ 来让他失去特殊意义才行。
场景1)至於 {} 的语法是这样的,假设我要找到两个 o 的字串,可以是:
(29)
(30)
(31)
【12.2.4】基础正则表达式字符
1)基础的正规表示法特殊字符汇整如下:
(32)
注意1:再次强调:『正则表达式的特殊字节』与一般在命令列输入命令的通配符并不相同, 例如,在通配符中的 * 代表的是『 0 ~ 无限多个字节』的意思,但是在正则表达式当中, * 则是『重复 0 到无穷多个的前一个 RE 字符』的意思。
【12.2.5】sed工具
1)sed 本身也是一个管线命令,可以分析 standard input 的啦! 而且 sed 还可以将数据进行取代、删除、新增、撷取特定行等等的功能呢!
(33)
2)以行为单位的新增/删除功能
(34)
补充:如果题型变化一下,举例来说,如果只要删除第 2 行,可以使用『 nl /etc/passwd | sed '2d' 』来达成, 至於若是要删除第 3 到最后一行,则是『 nl /etc/passwd | sed '3,$d' 』的啦,那个钱字号『 $ 』代表最后一行!
(35)
补充:在 a 后面加上的字串就已将出现在第二行后面罗!那如果是要在第二行前呢?『 nl /etc/passwd | sed '2i drink tea' 』就对啦!就是将『 a 』变成『 i 』即可。
【继续荔枝】:添加一行很简单,那如果是要增将两行以上呢?
(36)
3)以行为单位的取代与显示功能
(37)
(38)
(39)
4)部分数据的搜寻并取代的功能
除了整行的处理模式之外, sed 还可以用行为单位进行部分数据的搜寻并取代的功能喔! 基本上 sed 的搜寻与取代的与 vi 相当的类似!他有点像这样:sed 's/要被取代的字串/新的字串/g'
【荔枝】 文本内容如下:
(40)
(41)
(42)
(43)
(44)
【继续荔枝】假设我只要 MAN 存在的那几行数据, 但是含有 # 在内的注解我不想要,而且空白行我也不要!此时该如何处理呢?可以透过这几个步骤来实作看看:
(45)
(46)
(47)
空白行:包括有空格符的空白行,没有空格符的空白行;
5)直接修改文件内容(危险操作): sed 甚至可以直接修改文件的内容呢!而不必使用管线命令或数据流重导向! 不过,由於这个动作会直接修改到原始的文件,所以请你千万不要随便拿系统配置档来测试喔! 我们还是使用你下载的 regular_express.txt 文件来测试看看吧!
(48)
(49)
sed 的『 -i 』选项可以直接修改文件内容,这功能非常有帮助!举例来说,如果你有一个 100 万行的文件,你要在第 100 行加某些文字,此时使用 vim 可能会疯掉!因为文件太大了!那怎办?就利用 sed 啊!透过 sed 直接修改/取代的功能,你甚至不需要使用 vim 去修订!很棒吧!
【12.3】扩展正则表达式
1)为什么需要扩展正则表达式? 举个简单的例子好了,在上节的例题三的最后一个例子中,我们要去除空白行与行首为 # 的行列,使用的是
grep -v '^$' regular_express.txt | grep -v '^#'
需要使用到管线命令来搜寻两次!那么如果使用延伸型的正规表示法,我们可以简化为:
egrep -v '^$|^#' regular_express.txt
2)扩展正则表达式可以透过群组功能『 | 』来进行一次搜寻!那个在单引号内的管线意义为『或 or』啦! 是否变的更简单呢?此外,grep 默认仅支持基础正规表示法,如果要使用延伸型正规表示法,你可以使用 grep -E , 不过更建议直接使用 egrep !直接区分命令比较好记忆!其实 egrep 与 grep -E 是类似命令别名的关系啦!
3)扩展型正则表达式有哪几个特殊符号呢?
(50)
【荔枝】
(51)
(52)
(53)
(54)
(55)
【12.4】文件的格式化与相关处理
【12.4.1】格式化打印: printf
(56)
【荔枝】
(57)
补充: 在 printf 后续的那一段格式中,%s 代表一个不固定长度的字串,而字串与字串中间就以 \t 这个 [tab] 分隔符号来处理!你要记得的是,由於 \t 与 %s 中间还有空格,因此每个字串间会有一个 [tab] 与一个空白键的分隔喔!
(58)
补充:上面的格式共分为五个栏位, %10s 代表的是一个长度为 10 个字节的字串栏位,%5i 代表的是长度为 5 个字节的数字栏位,至於那个 %8.2f 则代表长度为 8 个字节的具有小数点的栏位,其中小数点有两个字节宽度。我们可以使用底下的说明来介绍 %8.2f 的意义:
字节宽度: 12345678
%8.2f意义:00000.00
如上所述,全部的宽度仅有 8 个字节,整数部分占有 5 个字节,小数点本身 (.) 占一位,小数点下的位数则有两位。
【继续荔枝】printf 除了可以格式化处理之外,他还可以依据 ASCII 的数字与图形对应来显示数据喔(注3)! 举例来说 16 进位的 45 可以得到什么 ASCII 的显示图 (其实是字节啦)?
(59)
16进制45 = 16*4+5 = 69, 而65~90 = A~Z;所以69表示E;
【12.4.2】awk:好用的数据处理工具
1)相较於 sed 常常作用於一整个行的处理,awk 则比较倾向於一行当中分成数个『栏位』来处理。因此,awk 相当的适合处理小型的数据数据处理呢!
2)awk 通常运行的模式是这样的:
[root@www ~]# awk '条件类型1{动作1} 条件类型2{动作2} ...' filename
awk 后面接两个单引号并加上大括号 {} 来配置想要对数据进行的处理动作。 awk 可以处理后续接的文件,也可以读取来自前个命令的 standard output 。
总结:awk 主要是处理『每一行的栏位内的数据』,而默认的『栏位的分隔符号为 "空白键" 或 "[tab]键" 』;
【荔枝】
(60)
分析1:由上面这个例子你也会知道,在每一行的每个栏位都是有变量名称的,那就是 $1, $2... 等变量名称。$0 代表『一整列数据』的意思~。
分析2:上述荔枝的整个 awk 的处理流程是:
1. 读入第一行,并将第一行的数据填入 $0, $1, $2.... 等变量当中;
2. 依据 "条件类型" 的限制,判断是否需要进行后面的 "动作";
3. 做完所有的动作与条件类型;
4. 若还有后续的『行』的数据,则重复上面 1~3 的步骤,直到所有的数据都读完为止。
经过这样的步骤,你会晓得, awk 是『以行为一次处理的单位』, 而『以栏位为最小的处理单位』。
3)awk 怎么知道我到底这个数据有几行?有几栏呢?这就需要 awk 的内建变量的帮忙啦~
(61)
【荔枝】我们继续以上面 last -n 5 的例子来做说明,如果我想要:
● 列出每一行的帐号(就是 $1);
● 列出目前处理的行数(就是 awk 内的 NR 变量)
● 并且说明,该行有多少栏位(就是 awk 内的 NF 变量)
则可以这样:
(62)
4)awk的逻辑运算符
(63)
【荔枝——利用 BEGIN 命令来预设了 awk变量】那假设我要查阅,第三栏小於 5 以下的数据,并且仅列出帐号与第三栏, 那么可以这样做:
(64)
有个问题:怎么第1行没有正确显示出来呢?
这是因为我们读入第一行的时候,那些变量 $1, $2... 默认还是以空白键为分隔的,所以虽然我们定义了 FS=":" 了, 但是却仅能在第二行后才开始生效。那么怎么办呢?我们可以预先配置 awk 的变量啊! 利用 BEGIN 这个关键字喔!这样做:
(65)
干货:这里利用 BEGIN 命令来预设了 awk变量;
【荔枝】利用awk来进行计算功能。对如下薪资表求总和:
[root@localhost chapter12]# cat pay.txt
Name 1st 2nd 3th
VBird 23000 24000 25000
DMTsai 21000 20000 23000
Bird2 43000 42000 41000
求和说明:我们可以这样考虑:
● 第一行只是说明,所以第一行不要进行加总 (NR==1 时处理);
● 第二行以后就会有加总的情况出现 (NR>=2 以后处理)
(66)
上面的例子有几个重要事项应该要先说明的:
● awk 的命令间隔:所有 awk 的动作,亦即在 {} 内的动作,如果有需要多个命令辅助时,可利用分号『;』间隔, 或者直接以 [Enter] 按键来隔开每个命令,例如上面的范例中,鸟哥共按了三次 [enter] 喔!
● 逻辑运算当中,如果是『等於』的情况,则务必使用两个等号『==』!
● 格式化输出时,在 printf 的格式配置当中,务必加上 \n ,才能进行分行!
● 与 bash shell 的变量不同,在 awk 当中,变量可以直接使用,不需加上 $ 符号。
(67)
cat pay.txt | awk 'NR==1{printf "%10s %10s %10s %10s %10s\n",$1, $2, $3, $4, "total"};
NR>=2 {total=$2+$3+$4;
printf "%10s %10d %10d %10d %10.2f\n",$1, $2, $3, $4, total}'
【继续荔枝】另外, awk 的动作内 {} 也是支持 if (条件) 的喔! 举例来说,上面的命令可以修订成为这样:
(68)
cat pay.txt | awk '{if(NR==1) printf "%10s %10s %10s %10s %10s\n",$1, $2, $3, $4, "total"};
{if(NR>=2) total=$2+$3+$4;
printf "%10s %10d %10d %10d %10.2f\n",$1, $2, $3, $4, total}'
总结: 第1种统计方法比较常用;
【12.4.3】文件比较工具
1)diff 命令:通常是用在同一的文件(或软件)的新旧版本差异上!
(69)
【荔枝】假如我们要将 /etc/passwd 处理成为一个新的版本,处理方式为: 将第四行删除,第六行则取代成为『no six line』,新的文件放置到 /tmp/test 里面,那么应该怎么做?
(70)
(71)
【继续荔枝】另外, diff 也可以比对整个目录下的差异喔!举例来说,我们想要了解一下不同的启动运行等级 (runlevel) 内容有啥不同?假设你已经知道运行等级 3 与 5 的启动脚本分别放置到 /etc/rc3.d 及 /etc/rc5.d , 则我们可以将两个目录比对一下:
(72)
2)cmp命令: cmp 主要也是在比对两个文件,他主要利用字节单位去比对, 因此,当然也可以比对 binary file 罗~(还是要再提醒喔, diff 主要是以『行』为单位比对, cmp 则是以字节为单位去比对,这并不相同!)
(73)
【荔枝】
(74)
3)cmp命令: diff 可以用来分辨两个版本之间的差异, 举例来说,刚刚我们所创建的 passwd.old 及 passwd.new 之间就是两个不同版本的文件。 那么,如果要『升级』呢?就是『将旧的文件升级成为新的文件』时,应该要怎么做呢? 其实也不难啦!就是『先比较先旧版本的差异,并将差异档制作成为补丁档,再由补丁档升级旧文件』即可。 举例来说,我们可以这样做测试:
(75)
(76)
补充: 以上面表格为例,新文件看到 - 会删除,看到 + 会加入!好了,那么如何将旧的文件升级成为新的内容呢? 就是将 passwd.old 改成与 passwd.new 相同!可以这样做:
(77)
(78)
(79)
【12.4.4】文件打印准备:pr
1) 如果我是在 Linux 底下列印纯文字档呢 可不可以具有标题啊?可不可以加入页码啊?呵呵!当然可以啊!使用 pr 就能够达到这个功能了。
【荔枝】举例来说,如果想要列印 /etc/man.config 呢?
(80)