linux读书摘要--正规表示法与文件格式化处理

声明:本文章为《鸟哥的Linux私房菜》读书摘要!



正规表示法

    正规表示法(Regular Expression, RE,或称为常规表示法)是透过一些特殊字符的排列,用以『搜寻/取代/删除』一列或多列文字字符串, 简单的说,正规表示法就是用在字符串的处理上面的一项『表示式』。正规表示法就是处理字符串的方法,他是以行为单位来进行字符串的处理行为, 正规表示法透过一些特殊符号的辅助,可以让使用者轻易的达到『搜寻/删除/取代』某特定字符串的处理程序!

    正规表示法的字符串表示方式依照不同的严谨度而分为: 基础正规表示法与延伸正规表示法。延伸型正规表示法除了简单的一组字符串处理之外,还可以作群组的字符串处理, 例如进行搜寻VBirdnetmanlman的搜寻,注意,是『或(or)』而不是『和(and)』的处理, 此时就需要延伸正规表示法的帮助。

    正规表示法与通配符是完全不一样的东西!通配符(wildcard)代表的是bash操作接口的一个功能』,但正规表示法则是一种字符串处理的表示方式。



基础正规表达法

语系对正规表示法的影响
    文件其实记录的仅有 01,我们看到的字符文字与数字都是透过编码表转换来的。由于不同语系的编码数据并不相同,所以就会造成数据撷取结果的差异了。 举例来说,在英文大小写的编码顺序中,zh_TW.big5C 这两种语系的输出结果分别如下:
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 

所以使用正规表示法时,需要特别留意当时环境的语系为何 

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

有些特殊符号需要我们记忆


grep的一些进阶选项

    grep 在数据中查寻一个字符串时,是以 " 整行 " 为单位来进行数据的撷取的! 』也就是说,假如一个文件内有 10 行,其中有两行具有你所搜寻的字符串,则将那两行显示在屏幕上,其他的就丢弃了!  


基础正规表示法练习 

练习前的设置
语系已经使用『export LANG=C; export LC_ALL=C』的设定值;
grep 已经使用 alias 设定成为『grep --color=auto

例题一、搜寻特定字符串
反向选择:也就是说,当该行没有'the'这个字符串时才显示在屏幕上 


如果你想要取得不论大小写的the这个字符串

例题二、利用中括号[]来搜寻集合字符
如果我想要搜寻 test taste这两个单字时,可以发现到,其实她们有共通的't?st'存在

其实[]里面不论有几个字符,他都仅代表某『一个』字符, 所以,上面的例子说明了,我需要的字符串是『tast』或『test』两个字符串而已
如果想要搜寻到有 oo 的字符时 


但是,如果我不想要oo前面有g的话

再来,假设我oo前面不想要有小写字符,所以,我可以这样写[^abcd....z]oo ,由于小写字符的ASCII上编码的顺序是连续的,也可以这样写 [^a-z]oo

由于考虑到语系对于编码顺序的影响,因此除了连续编码使用减号『-』之外, 你也可以使用如下的方法 


例题三、行首与行尾字符^ $

我们在例题一当中,可以查询到一行字符串里面有the的,那如果我想要让the只在行首列出 ,则需要制表符。

如果我想要开头是小写字符的那一行就列出

那个^符号,在字符集合符号(括号[])之内与之外是不同的! 在[]内代表『反向选择』,在 [] 之外则代表定位在行首的意义 

那如果我想要找出来,行尾结束为小数点(.)的那一行 



特别注意到,因为小数点具有其他意义(底下会介绍),所以必须要使用跳脱字符(\)来加以解除其特殊意义
不过,你或许会觉得奇怪,但是第 5~9 行最后面也是 . 啊~怎么无法打印出来? 这里就牵涉到Windows平台的软件对于断行字符的判断问题了!我们使用cat -A将第五行拿出来看, 你会发现:

LinuxWindows上的差异, 在上面的表格中我们可以发现5~9行为Windows的断行字符 (^M$) ,而正常的Linux应该仅有第10 行显示的那样($)。所以那个.自然就不是紧接在$之前喽。

如果我想要找出来,哪一行是『空白行』, 也就是说,该行并没有输入任何数据


不要空白行,不要#开头的注释行


例题四、任意一个字符.与重复字符*
我们知道通配符*可以用来代表任意(0或多个)字符, 但是正规表示法并不是通配符,两者之间是不相同的
 . (小数点):代表『一定有一个任意字符』的意思;
* (星星号):代表『重复前一个字符,0到无穷多次』的意思,为组合形态;

假设我需要找出g??d的字符串,亦即共有四个字符, 起头是g而结束是 



* 代表的是『 重复0个或多个前面的RE字符』的意义, 因此,o*』代表的是:『拥有空字符或一个o以上的字符』
当我们需要『至少两个 o 以上的字符串』时,就需要ooo*

如果我想要字符串开头与结尾都是g,但是两个g之间仅能存在至少一个o ,亦即是 gog, goog, gooog....等等

.*就代表零个或多个任意字符 



例题五、限定连续 RE 字符范围 {}
我想要找出两个到五个 o 的连续字符串,该如何作?这时候就得要使用到限定范围的字符{}了。 但因为{}的符号在shell是有特殊意义的,因此, 我们必须要使用跳脱字符\来让他失去特殊意义才行。

我们要找出g后面接25o,然后再接一个g 的字符串

如果我想要的是2
o 以上的 goooo....g呢?除了可以是gooo*g,也可以是go\{2,\}g

基础正规表示法字符汇整 (characters)



sed工具

sed本身也是一个管线命令,可以分析standard input的。sed还可以将数据进行取代、删除、新增、撷取特定行等等的功能

下面来看看具体的应用例程。


如果题型变化一下,举例来说,如果只要删除第2行,可以使用『nl /etc/passwd | sed '2d'』来达成,至于若是要删除第3 到最后一行,则是『nl /etc/passwd | sed '3,$d'』的啦,那个钱字号『$』代表最后一行! 


这个范例的重点是『我们可以新增不只一行喔!可以新增好几行』但是每一行之间都必须要以反斜杠『\』来进行新行的增加喔!所以,上面的例子中,我们可以发现在第一行的最后面就有\存在。

我们以前想要列出第11~20 行, 得要透过『head -n 20 | tail -n 10』之类的方法来处理,很麻烦啦~sed则可以简单的直接取出你想要的那几行。

除了整行的处理模式之外,sed 还可以用行为单位进行部分数据的搜寻并取代的功能喔! 基本上sed的搜寻与取代的与vi 相当的类似(注意与c功能的不同用法)

使用底下这个取得IP数据的范例,一段一段的来处理给您瞧瞧,让你了解一下什么是咱们所谓的搜寻并取代

假设我只要MAN存在的那几行数据, 但是含有# 在内的批注我不想要,而且空白行我也不要

直接修改文件内容(危险动作) 

sed的『-i』选项可以直接修改文件内容,这功能非常有帮助!举例来说,如果你有一个100万行的文件,你要在第 100 行加某些文字,此时使用 vim可能会疯掉!因为文件太大了!那怎办?就利用sed啊!透过 sed直接修改/取代的功能,你甚至不需要使用vim去修订。


延伸正规表示法
在上节的例题三的最后一个例子中,我们要去除空白行与行首为#的行列,使用的是
grep -v '^$' regular_express.txt | grep -v '^#'
需要使用到管线命令来搜寻两次!那么如果使用延伸型的正规表示法,我们可以简化为:
egrep -v '^$|^#' regular_express.txt
延伸型正规表示法可以透过群组功能『|』来进行一次搜寻!那个在单引号内的管线意义为『或 or』啦! 是否变的更简单呢?此外,grep预设仅支持基础正规表示法,如果要使用延伸型正规表示法,你可以使用grep -E, 不过更建议直接使用egrep!直接区分指令比较好记忆!其实egrepgrep -E是类似命令别名的关系


文件的格式化与相关处理

格式化打印: printf


printf.txt文件



我们将每个数据都以[tab]作为分隔,但是由于 Chinese长度太长,导致 English中间多了一个 [tab] 来将资料排列整齐
printf 后续的那一段格式中,%s代表一个不固定长度的字符串,而字符串与字符串中间就以\t这个 [tab]分隔符来处理!你要记得的是,由于\t%s中间还有空格,因此每个字符串间会有一个[tab]与一个空格键的分隔 。

%10s代表的是一个长度为10个字符的字符串字段, %5i 代表的是长度为 5个字符的数字字段,至于那个%8.2f则代表长度为 8 个字符的具有小数点的字段,其中小数点有两个字符宽度。我们可以使用底下的说明来介绍%8.2f的意义:
字符宽度: 12345678
%8.2f
意义: 00000.00 

awk:好用的数据处理工具

awk 也是一个非常棒的数据处理工具!相较于sed 常常作用于一整个行的处理,awk 则比较倾向于一行当中分成数个『字段』来处理

 

awk可以处理后续接
的文件,也可以读取来自前个指令的
standard output 。 但如前面说的,awk主要是处理『每一行
的字段内的数据』,而默认的『字段的分隔符为
"空格键""[tab]"!举例来说,我们用last
以将登入者的数据取出来,结果如下所示:

若我想要取出账号与登入者的IP,且账号与 IP之间以[tab] 隔开,则会变成这样:

上表是awk最常使用的动作!透过 print 的功能将字段数据列出来!字段的分隔则以空格键或[tab]按键来隔开。

awk 的括号内, 每一行的每个字段都是有变量名称的,那就是 $1, $2...等变量名称。以上面的例子来说,dmtsai $1,因为他是第一栏嘛!至于 192.168.1.100是第三栏, 所以他就是$3  


整个awk 的处理流程是:
1. 读入第一行,并将第一行的资料填入$0, $1, $2.... 等变数当中;
2. 依据"条件类型"的限制,判断是否需要进行后面的 "动作"
3. 做完所有的动作与条件类型;
4. 若还有后续的『行』的数据,则重复上面1~3 的步骤,直到所有的数据都读完为止。

经过这样的步骤,你会晓得, awk 是『 以行为一次处理的单位』, 而『以字段为最小的处理单位』。好了,那么awk 怎么知道我到底这个数据有几行?有几栏呢?这就需要awk 的内建变量的帮忙啦~ 

我们继续以上面last -n 5 的例子来做说明,如果我想要:
列出每一行的账号(就是$1)
列出目前处理的行数(就是awk 内的 NR变量)
并且说明,该行有多少字段(就是awk 内的 NF变量)
则可以这样:

awk的逻辑运算字符 



/etc/passwd 当中是以冒号":" 来作为字段的分隔, 该文件中第一字段为账号,第三字段则是UID。那假设我要查阅,第三栏小于10 以下的数据,并且仅列出账号与第三栏, 那么可以这样做:

有趣吧!不过,怎么第一行没有正确的显示出来呢?这是因为我们读入第一行的时候,那些变数$1,$2... 默认还是以空格键为分隔的,所以虽然我们定义了FS=":" 了, 但是却仅能在第二行后才开始生效。那么怎么办呢?我们可以预先设定awk 的变量啊! 利用 BEGIN 这个关键词 

awk的指令间隔:所有 awk 的动作,亦即在 {} 内的动作,如果有需要多个指令辅助时,可利用分号『;
间隔, 或者直接以
[Enter] 按键来隔开每个指令,例如上面的范例中,鸟哥共按了三次[enter] 喔!
逻辑运算当中,如果是『等于』的情况,则务必使用两个等号『 ==』!
格式化输出时,在 printf 的格式设定当中,务必加上 \n ,才能进行分行!
bash shell 的变量不同,在 awk 当中,变量可以直接使用,不需加上$ 符号。 


文件比对工具 

同一个软件包的不同版本之间,比较配置文件与原始档的差异』。 很多时候所谓的文件比对,通常是用在ASCII 纯文本档的比对上的。常用的文件对比指令有diff、cmp和patch

diff就是用在比对两个文件之间的差异的,并且是以行为单位来比对的!一般是用在 ASCII纯文本档的比对上。 由于是以行为比对的单位,因此 diff通常是用在同一的文件(或软件)的新旧版本差异上 

假如我们要将/etc/passwd 处理成为一个新的版本,处理方式为: 将第四行删除,第六行则取代成为『no six line』,新的文件放置到/tmp/test 里面,那么应该怎么做
 

接下来讨论一下关于diff 的用法

cmp主要也是在比对两个文件,他主要利用『字节』单位去比对, 因此,当然也可以比对 binary file啰~(还是要再提醒喔,diff 主要是以『行』为单位比对,cmp 则是以『字节』为单位去比对,这并不相同!

patch这个指令与 diff 可是有密不可分的关系啊!我们前面提到, diff可以用来分辨两个版本之间的差异, 举例来说,刚刚我们所建立的 passwd.old passwd.new 之间就是两个不同版本的文件。 那么,如果要『升级』呢?就是『 将旧的文件升级成为新的文件』时,应该要怎么做呢? 其实也不难啦!就是『先比较先旧版本的差异,并将差异档制作成为补丁档,再由补丁档更新旧文件』即可。

一般来说,使用diff 制作出来的比较文件通常使用扩展名为.patch 啰。至于内容就如同上面介绍的样子。 基本上就是以行为单位,看看哪边有一样与不一样的,找到一样的地方,然后将不一样的地方取代掉! 以上面表格为例,新文件看到- 会删除,看到 +会加入!好了,那么如何将旧的文件更新成为新的内容呢? 就是将 passwd.old改成与 passwd.new 相同!可以这样做:


文件打印准备:pr

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值