欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

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

程序员文章站 2022-05-06 11:28:41
...

1.  正则表达式的字符串表示方式依照不同的严谨度而分为: 基础正则表达式与延伸正则表达式。延伸正则表达式除了简单的一组字符串处理外,还可以作群组的字符串处理, 例如进行搜寻 VBird 或 netman 或 lman 的搜寻,此时就需要延伸正则表达式中特殊的『 ( 』与『 | 』等字符的帮助。

 

2.  为了要避免编码所造成的英文与数字的摘取问题,因此定义了一些特殊的符号:

特殊符号 代表意义
[:alnum:] 代表英文大小写字符及数字,即 0-9, A-Z, a-z
[:alpha:] 代表任何英文大小写字符,即 A-Z, a-z
[:blank:] 代表空格键与 [Tab]键
[:cntrl:] 代表控制按键,即 CR, LF, Tab, Del.. 等等
[:digit:] 代表数字,即 0-9 
[:graph:]  除了空格键与 [Tab] 键以外的其他所有按键
[:lower:]  代表小写字符,即 a-z
[:print:] 

代表任何可以被打印出来的字符

[:punct:] 代表标点符号,即:" ' ? ! ; : # $... 
[:upper:] 代表大写字符,即 A-Z
[:space:] 任何会产生空白的字符,包括空格键, [Tab], CR 等等
[:xdigit:] 代表 16 进制的数字类型,即: 0-9, A-F, a-f 的数字与字符

 

3.  grep 在数据中查寻一个字符串时,是以 "整行" 为单位来进行数据的摘取的。grep 的一些进阶用法:

# grep [-A] [-B] [--color=auto] '搜寻字符串' filename

-A选项后面可加数字,为 after 的意思,表示除了列出该行外,后续的 n 行也列出; -B为before的意思与-A选项类似;--color=auto 可将匹配的数据以不同颜色表示。

 

4.  [] 里面不论有几个字符,他都仅代表某『一个』字符。当我们在一组字符中,如果该字符组是连续的,比如数字与英文,就可以这样写:[a-zA-Z0-9]。考虑到语系对编码顺序的影响,除了连续编码使用减号『 - 』外,也可以使用:[[:digit:]]表示数字,[^[:lower:]]表示非小写英文字符。

 

5.  ^符号,在字符集合符号(括号[])之内与之外是不同的,在 [] 内代表『反向选择』,在 [] 外则代表行首。$符号代表行尾。

 

6.  grep -v '^$' /etc/syslog.conf | grep -v '^#' 可以去除文件中的空白行和以#号开头的行。

 

7.  正则表达式中『 . 』代表『绝对有一个任意字符』, * 代表『重复前一个 0 到无穷多次』的意思。『{m,n} 代表『重复前一个最少m次最多n次』的意思。但因为 {} 符号在 shell 中是有特殊意义的,因此, 我们必须要使用转义字符 \ 来让它失去特殊意义才行。

 

8.  正则表达式的特殊字符汇整如下:

字符 意义
^word 待搜寻的字符串(word)在行首
word$ 待搜寻的字符串(word)在行尾
. 代表『一定有一个任意字符』的字符
\ 转义字符,将特殊符号的特殊意义去除
* 重复零个到无穷多个的前一个字符
[list] 字符集合,里面列出想要摘取的字符
[n1-n2] 字符集合,里面列出想要摘取的字符范围
[^list] 字符集合,里面列出不要的字符串或范围
\{n,m\} 连续 n 到 m 个的『前一个字符』
\{n,\} 连续 n 个以上的前一个字符

 

9.  sed 本身也是一个管道命令,可以分析 standard input,将数据进行取代、删除、新增、摘取特定行等等的功能后输出:

 

sed [-nefr] [动作]
选项与参数说明如下:

 

选项 功能
-n 使用安静(silent)模式。在一般 sed 的用法中,所有来自 STDIN 的数据一般都会被列出到屏幕上。但如果加上 -n 参数后,则只有经过 sed 特殊处理的那一行(或动作)才会被列出来。
-e 直接在指令列模式上进行 sed 的动作编辑。
-f 直接将 sed 的动作写在一个档案内, -f filename 则可以执行 filename 内的 sed 动作;
-r sed 的动作支持的是延伸正则表达式的语法。(默认是基础正则表达式的语法)
-i 直接修改读取的档案内容,而不是由屏幕输出。

动作的格式如下:[n1[,n2]]function n1, n2 是可选的,一般代表『选择进行动作的行数』,如果我的动作是需要在 10 到 20 行之间进行的,则可以用『10,20[动作行为] 』。如果只有n1时,表示只对n1行进行操作,$代表最后一行。 sed 后面接的动作,请务必以 '' 两个单引号括住。 sed 后面如果要接超过两个以上的动作时,每个动作前面得加 -e 才行。

动作的说明如下:

 

动作 含义
a 新增, a的后面可以接字符串,而这些字符串会在新的一行出现(当前的下一行)
c 取代, c的后面可以接字符串,这些字符串可以取代 n1,n2之间的行
d 删除,d 后面通常不接任何东西
i 插入, i 的后面可以接字符串,而这些字符串会在新的一行出现(当前的上一行)
p 打印,亦即将某个选择的数据打印出。通常 p 会与参数 sed -n 一起
s 取代,通常这个 s 的动作可以搭配正则表达式,例如 1,20s/old/new/g

 

10.  除了整行地处理模式外, sed 还可以用行为单位进行部分数据的搜寻并替换的功能:

sed 's/要被取代的字符串/新癿字符串/g'

 

11.  延伸正则表达式可以通过群组功能『 | 』来进行一次搜寻,在单引号内的管道符意义为『或 or』。grep 默认仅支持基础正则表达式,如果要使用延伸正则表达式,你可以使用 grep -E ,不过更建议直接使用 egrep ,其实 egrep 与 grep -E 是类似命令别名的关系。

 

12.  延伸型的正则表达式有以下几个特殊符号:

 

字符 意义
+ 重复『一个或一个以上』的前一个字符
? 『零个或一个』的前一个字符
| 用或( or )的方式找出数个字符串
() 找出『群组』字符串
()+ 一个以上的多个重复群组

 

13.  printf 可以帮我们将资料输出的结果格式化(每一行都按照给出的格式进行格式化),而且支持一些特殊的字符:

 

# printf '打印格式' 实际内容
 printf 不是管道指令,打印格式中用到的特殊样式:

 

符号 意义
\a 警告声音输出
\b 退格键(backspace)
\f 清除屏幕 (form feed)
\n 输出新的一行
\r 亦即 Enter 按键
\t 水平的 [tab] 按键
\v 垂直的 [tab] 按键
\xNN NN 为两位数的数字,可以将16进制的ASCII码转成字符。
%ns 显示n个字符的字符串
%ni 显示n个位的整数
%N.nf 显示包括小数点在内的N位浮点数,其中小数点后n位

 

14.  相较于 sed 常常作用于一整个行的处理, awk 则比较倾向于一行当中分成数个『分段』来处理。因此,awk 相当适合处理小型的数据:

# awk '条件1{动作1} 条件2{动作2} ...' filename

awk 可以处理后续接的档案,也可以读取来自前个指令的 standard output 。 awk 主要是处理『每一行的分段内的数据』,而默认的『分段的分隔符为 "空格键" 或 "[tab]键" 』,每一行的每个分段都是有变量名称的,那就是 $1, $2... 等。$0 代表『一整行数据』。整个 awk 的处理流程是:

  1)  读入第一行,并将第一行的数据填入 $0, $1, $2.... 等变量中;

  2)  依据 "条件" 的限制,判断是否需要进行后面的 "动作";

  3)  对每一个条件进行判断,并依据判断结果执行之后的动作;

  4)  若还有后续的『行』的数据,则重复上面 1~3 的步骤,直到所有的数据都读完为止。

awk 还有几个特殊的内建变量(无需用$取值):NF表示每行($0)拥有的分段总数,NR表示目前 awk 所处理的是『第几行』数据,FS表示目前的分隔字符,默认是空格键。所有 awk 的动作,亦即在 {} 内的动作,如果有需要多个指令辅助时,可利用分号『;』间隔,或者直接以 [Enter] 按键来隔开每个指令。

 

15.  在 /etc/passwd 当中是以冒号 ":" 作为字段的分隔,该档案中第一字段为账号,第三字段则是 UID。那假设我要查阅,第三栏小于 10 以下的数据,并且仅列出账号与第三栏:

 

# cat /etc/passwd | \ > awk '{FS=":"} $3 < 10 {print $1 "\t " $3}' 
root:x:0:0:root:/root:/bin/bash 
bin 1 
daemon 2
...

我们读入第一行的时候,那些变量 $1, $2... 默认还是以空格键为分隔的,所以虽然我们定义了 FS=":" 了, 但是即仅能在第二行后才开始生效,可以利用 BEGIN 这个关键字预先定义awk的变量:

 

# cat /etc/passwd | \ > awk 'BEGIN {FS=":"} $3 < 10 {print $1 "\t " $3}' 
root 0 
bin 1 
daemon 2
 

 

16.  diff 就是用在比对两个档案之间的差异,并且是以行为单位来比对的,一般是用在 ASCII 纯文本档的比对上。 

 

 

# diff [-bBi] from-file to-file
选项与参数说明如下:

 

选项 功能
-b 忽略一行当中仅有多个空白的差异(例如 "about me" 与 "about    me" 视为相同)
-B 忽略空白行的差异。
-i 忽略大小写的不同。

举例:

 

# cp /etc/passwd passwd.old
# cat /etc/passwd | sed -e '4d' -e '6c no six line' > passwd.new
# diff passwd.old passwd.new 4d3 <==左边第四行被删除 (d) 掉了,基准是右边的第三行 
< adm:x:3:4:adm:/var/adm:/sbin/nologin <==这里列出左边(<)档案被删除的那一行内容 6c5 <==左边档案的第六行被取代 (c) 成右边档案的第五行 
< sync:x:5:0:sync:/sbin:/bin/sync <==左边(<)档案第六行内容 
--- 
> no six line <==右边(>)档案第五行内容
diff 也可以比对整个目录下的差异,执行等级 3 与 5 的启动脚本分别放在 /etc/rc3.d/etc/rc5.d , 则我们可以将两个目录进行比对:

 

 

# diff /etc/rc3.d/ /etc/rc5.d/ 
Only in /etc/rc3.d/: K99readahead_later 
Only in /etc/rc5.d/: S96readahead_later
 

 

17.  cmp 主要也是在比对两个档案,他主要利用『字节』单位去比对, 因此,可以用于比对 binary file:

 

# cmp [-s] file1 file2
-s :将所有的不同点的字节处都列出来。因为 cmp 默认仅会输出第一个发现的不同点。

 

 

18.  diff 可以加上-Naur 参数生成patch文件:

 

# diff -Naur passwd.old passwd.new > passwd.patch
patch指令可以用这个patch文件对旧版的文件进行更新,或对更新后的文件进行还原:

 

 

# patch -p0 < passwd.patch 
patching file passwd.old 
# ll passwd* 
-rw-r--r-- 1 root root 1929 Feb 10 14:29 passwd.new 
-rw-r--r-- 1 root root 1929 Feb 10 15:12 passwd.old <==档案一模一样! 

# patch -R -p0 < passwd.patch 
# ll passwd* 
-rw-r--r-- 1 root root 1929 Feb 10 14:29 passwd.new 
-rw-r--r-- 1 root root 1986 Feb 10 15:18 passwd.old
 

 

19.  pr 处理后后文件会为每一页产生一个标题,标题中会有『档案时间』、『档案档名』及『页码』三大项目。

 

20.  由于指令列的内容长度是有限制的,因此当搜寻的对象是整个系统时,下述癿指令会发生错误:

 

# grep '\*' $(find / -type f) 
-bash: /bin/grep: Argument list too long
此时可以通过管道命令以及 xargs 来处理,每次丢 10 个给 grep 来作为参数处理:

 

# find / -type f | xargs -n 10 grep '\*'

grep 加上 -l 参数会只列出档名而不是匹配的行的内容。

 

21.  关于 awk 的进阶文献:

    中研院计算中心 ASPAC 计划之 awk 程序介绍:http://phi.sinica.edu.tw/aspac/reports/94/94011/

    鸟哥备份:http://linux.vbird.org/linux_basic/0330regularex/awk.pdf  

    Study Area:http://www.study-area.org/linux/system/linux_shell.htm