为什么语系的数据会影响到正则表达式的输出结果呢?我们在[第零章计算机概论的文字编码系统]里面谈到,文件其实记录的仅有 0 与 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 也会被撷取出来!因为就编码的顺序来看, big5 语系可以撷取到“ A b B c C ... z Z ”这一堆字符哩! 所以,使用正则表达式时,需要特别留意当时环境的语系为何, 否则可能会发现与别人不相同的撷取结果喔!
至于本章的练习用文件请由下面的链接来下载。需要特别注意的是,下面这个文件是鸟哥在 MS Windows 系统下编辑的, 并且已经特殊处理过,因此,他虽然是纯文本文件,但是内含一些 Windows 系统下的软件常常自行加入的一些特殊字符,例如断行字符 (^M) 就是一例! 所以,你可以直接将下面的文字以 vi 储存成 regular_express.txt 这个文件, 不过,还是比较建议直接点下面的链接:
[dmtsai@study ~]$ vi regular_express.txt"Open Source"isagoodmechanismtodevelopprograms.appleismyfavoritefood.Footballgameisnotusefeetonly.thisdressdoesn't fit me.However, this dress is about $ 3183 dollars.^MGNU is free air not free beer.^MHer hair is very beauty.^MI can'tfinishthetest.^MOh!Thesouptastegood.^Mmotorcycleischeapthancar.Thiswindowisclear.thesymbol'*'isrepresentedasstart.Oh!Mygod!Thegdsoftwareisalibraryfordraftingprograms.^MYouarethebestismeanyouaretheno.1.Theworld<Happy>isthesamewith"glad".Ilikedog.googleisthebesttoolsforsearchkeyword.goooooogleyes!go!go!Let's go.# I am VBird
这文件共有 22 行,最下面一行为空白行!现在开始我们一个案例一个案例的来介绍吧!
例题一、搜寻特定字串
搜寻特定字串很简单吧?假设我们要从刚刚的文件当中取得 the 这个特定字串,最简单的方式就是这样:
[dmtsai@study ~]$ grep -n 'the' regular_express.txt8:Ican't finish the test.12:the symbol '*' is represented as start.15:You are the best is mean you are the no. 1.16:The world <Happy> is the same with "glad".18:google is the best tools for search keyword.
你会发现,屏幕上出现的行列为除了 8,12,15,16,18 五行之外的其他行列! 接下来,如果你想要取得不论大小写的 the 这个字串,则:
[dmtsai@study ~]$ grep -in 'the' regular_express.txt8:Ican't finish the test.9:Oh! The soup taste good.12:the symbol '*' is represented as start.14:The gd software is a library for drafting programs.15:You are the best is mean you are the no. 1.16:The world <Happy> is the same with "glad".18:google is the best tools for search keyword.
除了多两行 (9, 14行) 之外,第 16 行也多了一个 The 的关键字被撷取到喔!
例题二、利用中括号 [] 来搜寻集合字符
如果我想要搜寻 test 或 taste 这两个单字时,可以发现到,其实她们有共通的 't?st' 存在~这个时候,我可以这样来搜寻:
[dmtsai@study ~]$ grep -n 't[ae]st' regular_express.txt8:Ican't finish the test.9:Oh! The soup taste good.
此时,就只剩下第 12 行,因为只有第 12 行的行首是 the 开头啊~此外, 如果我想要开头是小写字符的那一行就列出呢?可以这样:
[dmtsai@study ~]$ grep -n '^[a-z]' regular_express.txt2:appleismyfavoritefood.4:thisdressdoesn't fit me.10:motorcycle is cheap than car.12:the symbol '*' is represented as start.18:google is the best tools for search keyword.19:goooooogle yes!20:go! go! Let'sgo.
[dmtsai@study ~]$ grep -n '\.$' regular_express.txt1:"Open Source"isagoodmechanismtodevelopprograms.2:appleismyfavoritefood.3:Footballgameisnotusefeetonly.4:thisdressdoesn't fit me.10:motorcycle is cheap than car.11:This window is clear.12:the symbol '*' is represented as start.15:You are the best is mean you are the no. 1.16:The world <Happy> is the same with "glad".17:I like dog.18:google is the best tools for search keyword.20:go! go! Let'sgo.
特别注意到,因为小数点具有其他意义(下面会介绍),所以必须要使用跳脱字符(\)来加以解除其特殊意义! 不过,你或许会觉得奇怪,但是第 5~9 行最后面也是 . 啊~怎么无法打印出来? 这里就牵涉到 Windows 平台的软件对于断行字符的判断问题了!我们使用 cat -A 将第五行拿出来看, 你会发现:
[dmtsai@study ~]$ cat -An regular_express.txt | head -n 10 | tail -n 65However,thisdressisabout $ 3183dollars.^M$6GNUisfreeairnotfreebeer.^M$7Herhairisverybeauty.^M$8Ican't finish the test.^M$ 9 Oh! The soup taste good.^M$ 10 motorcycle is cheap than car.$
我们在[第九章内谈到过断行字符]在 Linux 与 Windows 上的差异, 在上面的表格中我们可以发现 5~9 行为 Windows 的断行字符 (^M$) ,而正常的 Linux 应该仅有第 10 行显示的那样 ($) 。所以啰,那个 . 自然就不是紧接在 $ 之前喔!也就捉不到 5~9 行了!这样可以了解 ^ 与 $ 的意义吗? 好了,先不要看下面的解答,自己想一想,那么如果我想要找出来,哪一行是“空白行”, 也就是说,该行并没有输入任何数据,该如何搜寻?
意义:连续 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
范例四:我想将第2-5行的内容取代成为“No2-5number”呢?[dmtsai@study ~]$ nl /etc/passwd | sed '2,5c No 2-5 number'1root:x:0:0:root:/root:/bin/bashNo2-5number6sync:x:5:0:sync:/sbin:/bin/sync.....(后面省略).....
让我们再来继续研究 sed 与正则表达式的配合练习!假设我只要 MAN 存在的那几行数据, 但是含有 # 在内的注解我不想要,而且空白行我也不要!此时该如何处理呢?可以通过这几个步骤来实作看看:
步骤一:先使用grep将关键字MAN所在行取出来[dmtsai@study ~]$ cat /etc/man_db.conf | grep 'MAN'# MANDATORY_MANPATH manpath_element# MANPATH_MAP path_element manpath_element# MANDB_MAP global_manpath [relative_catpath]# every automatically generated MANPATH includes these fields....(后面省略)....步骤二:删除掉注解之后的数据![dmtsai@study ~]$ cat /etc/man_db.conf | grep 'MAN'| sed 's/#.*$//g'MANDATORY_MANPATH/usr/man....(后面省略)....# 从上面可以看出来,原本注解的数据都变成空白行啦!所以,接下来要删除掉空白行[dmtsai@study ~]$ cat /etc/man_db.conf | grep 'MAN'| sed 's/#.*$//g' | sed '/^$/d'MANDATORY_MANPATH/usr/manMANDATORY_MANPATH/usr/share/manMANDATORY_MANPATH/usr/local/share/man....(后面省略)....
直接修改文件内容(危险动作)
你以为 sed 只有这样的能耐吗?那可不! sed 甚至可以直接修改文件的内容呢!而不必使用管线命令或数据流重导向! 不过,由于这个动作会直接修改到原始的文件,所以请你千万不要随便拿系统配置文件来测试喔! 我们还是使用你下载的 regular_express.txt 文件来测试看看吧!
范例六:利用sed将regular_express.txt内每一行结尾若为.则换成![dmtsai@study ~]$sed-i's/\.$/\!/g'regular_express.txt# 上头的 -i 选项可以让你的 sed 直接去修改后面接的文件内容而不是由屏幕输出喔!# 这个范例是用在取代!请您自行 cat 该文件去查阅结果啰!范例七:利用sed直接在regular_express.txt最后一行加入“#Thisisatest”[dmtsai@study ~]$ sed -i '$a # This is a test' regular_express.txt# 由于 $ 代表的是最后一行,而 a 的动作是新增,因此该文件最后新增啰!
sed 的“ -i ”选项可以直接修改文件内容,这功能非常有帮助!举例来说,如果你有一个 100 万行的文件,你要在第 100 行加某些文字,此时使用 vim 可能会疯掉!因为文件太大了!那怎办?就利用 sed 啊!通过 sed 直接修改/取代的功能,你甚至不需要使用 vim 去修订!很棒吧!
总之,这个 sed 不错用啦!而且很多的 shell script 都会使用到这个指令的功能~ sed 可以帮助系统管理员管理好日常的工作喔!要仔细的学习呢!