您的位置:首页 > 其它

第十二章 正则表达式与文件格式化处理

2016-01-30 19:58 351 查看
12.1 前言

  这里鸟哥讲了正则表达式是什么用途,以及和通配符之间的区别。作用就是字符串查找、删除、替换等,可以用于在一堆文件中查找关键字,这个可以应用于垃圾邮件的查找。

12.2 基础正则表达式(grep)

12.2.1 一些特殊符号

特殊符号代表意义
[:alnum:]英文字母和数字,即a-z,A-Z,0-9
[:alpha:]英文字母
[:blank:]空格和Tab
[:cntrl:]键盘上的控制按键,如CR,LF,Tab,Del
[:digit:]数字
[:graph:]除了空格符(空格和Tab)之外的其他按键
[:lower:]小写字母
[:print:]任何可以被打印出来的字符
[:punct:]标点符号
[:upper:]大写字母
[:space:]任何会产生空格的字符,包括空格键[Tab] CR等
[:xdigit:]十六进制数字,包括0-9,a-f,A-F
12.2.2 grep的高级参数

  (1)显示内核信息

  (2)显示内核信息中包括"eth"(也就是网卡)的信息

  (3)将关键字显色,并加上行数

  (4)将关键字所在的行的前三行和后两行也显示

下面是执行效果:

(1)dmesg



(2)dmesg | grep ‘eth’



(3)dmesg | grep -n –color=auto ‘eth’



(4)dmesg | grep -A3 -B2 -n –color=auto ‘eth’



–color=auto可能是经常要用的功能,怎么样可以不用每次执行grep的时候都把加上去?修改~/.bashrc,加上alias grep=’grep –color=auto’,然后用source ~/.bashrc就可以:





注意在.bashrc里面空格不能随便加,很容易报错

12.2.3 基础正则表达式练习

首先用'wget http://linux.vbird.org/linux_basic/0330regularex/regular_express.txt '指令下载regular_express.txt

例题一:查找特定字符串

  (1)查找txt中含有'the'的行

  (2)反向选择:没有'the'的行

  (3)不论大小写的'the'

(1) grep -n 'the' regular_express.txt



(2) grep -nv 'the' regular_express.txt



(3) grep -in 'the' regular_express.txt



例题二:利用中括号来查找集合字符

  (1)同时查找'test'和'taste'(都含有t?st)

  (2)'oo'前面不能有'g'

  (3)'oo'前面不能有小写字母

  (4)含有数字

(1) 注意中括号里面不管有多少个字母,实际表示的就是一个字母



(2)[^]表示集合字符的反向选择



为什么第18、19行也被选中了呢?因为18行还有一个字符串"tools"也符合要求,19行有很多个o连在一起,所以会出现两个o的前面是o的情况。

(3)这题有多种写法,可以用[a-z]取小写字母,也可以用之前提到的特殊字符集合[:lower:]



(4)同(3)也有两种可行做法



注意中括号:在特殊字符中本身带有一对中括号,然后如果表示字符集合还要有一对中括号,所以如果要用特殊字符集表示集合字符,至少要有两对中括号

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

  (1)查找只在行首出现的"the"所在行

  (2)开头是小写字母

  (3)开头不是英文字母

  (4)行尾以小数点.结束

  (5)找出哪一行是空白行

  (6)以/etc/syslog.conf为例,找出除了以#为开头的行和空白行之外的行

(1)"^the"



(2)



(3)



(4)注意小数点是特殊字符(后面会讲)所以需要转义



第5-9行没有被选中的原因是windows的断行字符是^M$和Linux不一样。Linux就是$。

(5)这个需要动点脑筋:只有行首和行尾怎么表示?



(6)这题可以用两次grep去做,中间用"|"隔开就行了,另外就是取反的-v,也是很有用的



注意:^放在中括号里面表示取反,放在外面表示行首

例题四:任何一个字符.与重复字符*

首先说明一下这两个字符的含义:'.'表示任何一个字符;'*'表示重复前面一个字符0到无穷多次,所以它必须和其他字符组合使用,这个含义与通配符中的'*'不太一样。通配符中的'*'相当于正则表达式的'.*'

  (1)找出"g??d"字符串

  (2)列出含有"oo"、"ooo"、"oooo"的行

  (3)字符串开头和结尾都是g,中间仅能有至少一个o

  (4)g开头g结尾的字符串,中间字符可有可无

  (5)任意数字的行

(1)



(2)注意:至少要有两个'o',而'*'又是从0个开始的,所以最后要写三个o



(3)



(4)".*"表示任意的0个或多个字符,注意不是任意字符重复0或多次,因为.本身表示的不是一种字符,而是一个字符集。这个在第五题有体现:0个或多个任意数字,可以用"[[:digit:]]*"表示。



(5)



例题五:限定连续字符的范围

如果要找重复2~5个o,那么必须用限定范围的{}才能做到,但是由于在shell中{与}是有特殊作用的,所以要用转义字符让它们失去意义才可以。

  (1)找含有两个'o'的字符串

  (2)g后面接2~5个o,再接一个g

  (3)g后面接两个以上的o再接g

(1)



(2)



(3)



最后再提醒一下注意通配符的*和正则表达式中的*的含义的不同。

例题:以"ls -l"配合找出/etc文件夹下面所有类型为连接文件的文件名



12.2.4 sed工具

  sed是一个管道工具,可以用来分析standard input,而且也可以完成数据的替换、删除、新增、选取等功能。也就是说不仅可以查找还可以进行其他操作,这一点是grep不具有的

12.2.4.1 以行为单位的新增/删除功能

  (1):将/etc/passwd的内容打印出来并显示行号,同时将2~5行删除

  (2):在上例的基础上,在第二行后面加上"drink tea?"字样

(1)这题是基本的语法,可以有其他扩展,比如要删除2到最后一行(2, $)



(2)注意:a和i的功能都是插入字符串,但是a是在当前行的下面插入,而i是在当前行的上一行插入



另外如果要插入多行,在命令行中输入的时候,每一行末尾都要有一个反斜杠\

12.2.4.2 以行为单位的替换和显示功能

  (1)将2~5行的内容替换成"&No 2-5 Number"

  (2)将5到7行显示出来

(1)这里用到的是'c'的替换方法



(2)虽然p就表示打印,但是如果不加安静模式,5到7行会重复输出。所以-n还是很有用的

非安静模式:



安静模式:



12.2.4.3 部分数据的查找和替换功能

前面知道替换行可以用c实现,那么替换字符串可以怎么实现呢?可以用下面的指令:

sed ‘s/要被替换的字符串/新字符串/g’

现在以取得IP为范例,了解字符串替换怎么用:

步骤一:查看源信息,利用/sbin/ifconfig查询ip



步骤二:用grep筛选出含有ip地址的那一行



步骤三:将ip前面的部分删除



步骤四:将ip后面的部分删除



  可以看到,之前sed用来增加、删除和c替换都还没有用到正则表达式,但是在s替换就用上了,这是因为s是字符串的替换。所以学到这里对我认为正则表达式就是一个字符串,通过添加一些符号,还可以设定字符串中字符的类型、字符串的长度以及字符串的位置等。

  最后再看看一个sed和正则表达式结合的例子:只要存在MAN字样的数据,但是#注释行不要,空白行也不要

步骤一:用grep筛选出含有MAN的行



步骤二:将#后面的数据删除,这之后会产生一些空白行



步骤三:将空白行删除(用grep或sed都可以)





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

参数:-i

  (1)将regular_express.txt每一行结尾的'.'换成'!'

  (2)在最后一行加入"# This is a test"

(1)



(2)



注:使用-i进行文件修改的时候,不要使用安静模式-n,否则会把本来有的文本全部删除掉,我暂时不知道原因是什么。

  通过对sed的学习我们了解到它在文本管理上有很强的功能,比如在一些很长的文本中可以很轻松地在任一行之后添加文本,而不必再用vim打开之后一行行翻。

12.3 扩展正则表达式

为什么需要扩展正则表达式?之前我们发现删除所有的空白行和注释行需要通过两次筛选才能实现,中间通过'|'隔开。但是如果使用扩展正则表达式,一次就可以实现:

egrep -v '^$&|^#apos;

在这里的'|'也是或的意思。看起来比基础正则表达式简洁一些。其实用grep -E 也可以实现扩展,但是egrep更容易记忆。

下面看看扩展正则表达式中有哪些特殊的字符吧:

(1) + 表示重复前一个字符一次或多次

举例:要找"god"、"good"、"goood"等的字符串



(2) ? 零个或1个前一个RE字符

举例:找出"gd"和"god"这两个字符串



所以(1)和(2)的集合就是基础正则表达式中的*

(3) | 或关系筛选

举例:查找"gd"、"good"这两个字符串。如果还想找到"dog"呢?



(4) ()找出组字符串

举例:找出glad、good这两个字符串(它们的开头和结尾的字母都一样)



(5) ()+多个重复组的判别

举例:



12.4 文件的格式化与相关处理

让文本输出得更有型

12.4.1 格式化打印:printf

  printf在学习C++的时候已经用过很多了,但是在Linux中还可以在终端上配合cat来输出文件的内容。比如现在有一个printf.txt:



  现在我们用printf将它输出看一下是什么效果:



  可以看到由于Chinese的长度较长,和English中间多了一个Tab才将数据对齐。

  接下来说说浮点数输出的问题。%8.2f这个表示什么意思?"8"的意思是最后输出的这个数字总共占8个宽度(包括小数点),但是,如果整数部分太长,最后占的宽度会超过8。"2"的意思是小数部分保留两位,这个是可以确定的,不会因为数字的长度或者是总宽度的限制而改变。



  这个就是整数部分太长导致最终的宽度超过8。那如果小于8呢?



  可以看到在"12.35"前面还有三个空格,所以最终整个数字占有8个宽度。

  printf还有一个功能就是输出十六进制数对应的字符(Ascii码)



12.4.2 awk:好用的数据处理工具

相比起sed对整行数据的处理,awk可以对小型的数据段进行处理

12.4.2.1 awk的处理流程和内置变量

  首先,awk的处理单位是字段,读取单位是行。也就是说,awk一开始会读取第一行,然后将这一整行的数据赋值给$0,接着把每一个单词依次赋值给$1、$2……。所以$i(i>0)的数据也可以理解成第i列的数据。最后再读取下一行的数据,重复刚才的过程。

  (1)用last列出前五个登录用户的信息

  (2)在(1)的基础上再列出登录名和ip(第一列和第三列)





  另外awk还有三个内置变量,有特殊的代表意义:

变量名称代表意义
NF每一行($0)拥有的字段总数
NF目前awk处理的是第几行数据
FS目前的分隔字符,默认是空格键
如下例:



  注意内置变量不需要在前面加上$。

  

12.4.2.2 awk的逻辑运算符

  运算符和一般的语言的运算符相同,关键是在哪里进行判断。

  举例:在/etc/passwd中用":"作为字段的分隔,第一字段为账号,第三字段为UID,现在要输出UID小于10的账号和UID:



  但是这样第一行的数据有些问题:依然没有按照":"分隔,从第二行开始FS=":"才生效。这个时候需要利用BEGIN作为关键字:



12.4.2.3 awk用于判断和计算



必须现在要输出pay.txt的内容还要输出每个人的支出和。

我们可以这样考虑:第一行不用考虑,之后的行将$2、$3、$4求和



  注意awk中多个命令连接(这个例子中是运算和printf)可以用分号或者enter。在这里我用分号。然后判断条件放在"{}"的外面,命令放里面。当然如果用if语句,判断条件也可以放里面。不过如果if里面有多条语句,也要用大括号括起来。



语句:

12.4.3 文件比较工具

12.4.3.1 diff

  首先我们将/etc/passwd复制到自己的文件夹,并将第四行删除、第六行替换成"no six line"



注意:sed进行超过一个动作,每一个动作前面必须有-e。

接下来看看diff的用法:

diff [-bBi] from_file to_file

from_file表示需要被比较的文件,to_file表示与from_file进行比较的文件名。-b表示忽略多个空格和一个空格的区别,-B表示忽略空白行的比较(也就是一开始先去除空白行),-i表示忽略大小写。

  范例一:比较passwd.new和passwd.old



  所以diff的用途一般是比较同一个文件的不同版本上,用diff比较两个不同的文件没有意义。

  范例二:比较等级3和等级5的启动脚本



12.4.3.2 cmp

  和diff的区别是,diff以行为单位,cmp以字节为单位。

  范例一:用cmp比较passwd.old和passwd.new



  注意cmp默认只会列出第一处不同。如果要把所有结果列出要加上-s(经过实测,-s的用途并不是这样,而是返回一个数,如果两个文件相同,返回0,也就是true,这里和一般的语言不一样……否则返回1,执行错误返回2)

12.4.3.3 patch

  这个和diff联系在一起:diff用于比较同一个文件的不同版本,patch则用来将旧版本更新。过程是先将两个版本的区别制作为补丁文件,再通过补丁文件更新旧文件。

  范例一:以passwd.old和passwd.new制作补丁文件



-a:所有文件都视为文本文件来比较

-u:使用统一的输出格式

-r:当比较目录时,以递归的方式找到任何的子目录

  下面看看怎么用patch更新文件或恢复文件:

更新:patch -pN < patch_file

还原:patch -R -pN < patch_file

  范例二:将passwd.old变成与passwd.new相同



可以看到passwd.new和passwd.old一模一样

  范例三:恢复旧文件的内容



  可以看到两个文件又不一样了

  这个例子中由于比较的两个文件在同一个文件夹下,所以不需要减去目录,如果要比较目录,就要根据patch所在的目录进行目录的删减。

12.4.4 文件打印准备:pr

  鸟哥在这里对pr只是起了个头,说明一下它在打印文本方面具有更多的功能,比如具有标题和设置页码。



  上面输出的第一行就是pr特殊处理后的标题,包括文件时间、文件名和页码。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: