Liunx学习笔记 - 07 - 02 正则表达式与文件格式化处理

Liunx学习笔记 - 07 - 02 正则表达式与文件格式化处理

1 前言:啥是正则表达式

简单来讲,正则表达式是处理字符串的方法,它是以行为单位来进行字符串的处理行为,正则表达式通过一些特殊符号的辅助,可以让用户轻易实现查找、删除、替换某特定字符串。

正则表达式基本上是一种“表示法”,只要工具程序支持这种表示方法,那么该工具程序就可以用来作为正则表达式的字符串处理之用。例如:vi、grep、awk、sed等工具,它们本身支持正则表达式,故可以使用正则表达式的特殊字符来进行字符串处理。但是例如ls、cp等命令并不支持正则表达式,所以只能使用bash自身的通配符。注意,通配符(*、?、[]、[-]、[^])并不是正则表达式,两者是不一样的概念。

换而言之,使用ls、cp等命令时,某些符号是做通配符来使用的;而使用vi、grep、awk、sed等工具时,某些符号是做正则表达式来使用的,两者的意义功能是不一样的。

正则表达式分为基础正则表达式和扩展正则表达式

2 基础正则表达式

2.1 特殊符号表

特殊符号代表意义
[: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:]代表标点符号(punctuation symbol),即" ’ ? ! ; : # $
[:upper:]代表大写字符,即A-Z
[:space:]代表会产生空白的字符,包括空格键 [Tab] CR等
[:xdigit:]代表16进制的数字类型,包括0-9,A-F,a-f的数字与字符

实际上,最常用的莫过于[:alnum:]、[:alpha:]、[:upper:]、[:lower:]、[:digit:]。

2.2 grep的高级参数

用法:
grep [-A] [-B] [--color=auto] ‘搜寻字符串’ filename
参数:
-A 后面可加数字,表示after的意思,除了列出该行外,还将后续n行也列出来
-B 后面可加数字,表示before的意思,除了列出该行外,还将先前的n行也列出来
--color=auto 将符合字符串的用特殊颜色标识(不设也没关系,默认就是有颜色的)

例:
dmesg查看内核信息,|管道符,grep匹配eth相关字符所在行并输出,同时将找到行的前2行和后3行也输出,还标示行号,如下:

dmesg | grep -n -A3 -B2 'eth'

2.3 基础正则表达式

基础正则表达式特殊字符归纳表(假设文件为fileName.txt)

特殊符号意义范例
^word待查找的字符串word在行首查找以#开始的行,并列出行号grep -n ‘^#’ fileName.txt
word$待查找的字符串word在行尾将行尾为!的行输出,并列出行号grep -n ‘!$’ fileName.txt
.代表一定有一个任意的字符可以是aaa、aba、a a等,但不能是aagrep -n ‘a.a’ fileName.txt
\转义字符,让特殊符号失去意义查找含有单引号的那一行grep -n \’ fileName.txt
*重复0个到无穷多个前一个字符可以是sb、sbb、sbbb等字符grep -n ‘sbb*’ fileName.txt
[list]代表1个列表中的字符查找mgh、mgq、mgygrep -n ‘mg[hqy]’ fileName.txt
[n1-n2]代表字符范围内的1个字符查找class1、class2……class9grep -n ‘class[1-9]’ fileName.txt
[^list]不是列表中的1个字符m后接1个字符,但不能是mb、mcgrep -n ‘m[^bc]’ fileName.txt
\{n,m\}连续n-m个前一个字符可以是moon、mooongrep -n ‘mo\{2,3\}n’ fileName.txt

注意:

在正则表达式中,*(asterisk星号)的用法比较诡异,其代表重复0到无穷多个前一个字符,所以如果要查找sb、sbb、sbbb,即至少有1个b的字符,那么实际上你要敲成sbb* 才行的,即至少写俩b才行,因为sbb*代表sb之后紧接着有0到无穷个的b存在!!

而在通配符中,*(asterisk星号)则表示0到无限多个任意字符的意思,两者意义不同,不可混淆。

^ 符号在中括号外面,即^[list]表示行首为list中字符打头;而 ^ 符号在中括号里面,即[^list]表示反选list中字符。

2.4 基础正则表达式的示例,以grep为例

先写个testFile.txt来做grep查找,文件内容如下

God bless me!
Oh, my god!
What's your name?
Happy new year!

Goodbye.
Time to say goodbye.
Goood evening.
Gooood morning.

例1-查找特定字符串:

grep -n 'me' testFile.txt	# 查找含字符串'me'的行,并显示行号,结果如下:
1:God bless me!
3:What's your name?
7:Time to say goodbye.
grep -n 'god' testFile.txt	# 查找含字符串'god'的行,如下(注意是区分大小写的):
2:Oh, my god!
grep -in 'god' testFile.txt	# 不区分大小写查找含字符串'god'的行,加-i即可,如下:
1:God bless me!
2:Oh, my god!
grep -vn 'm' testFile.txt # 查找不含'm'字符串的行,如下:
4:Happy new year!
5:
6:Goodbye.
8:Goood evening.

例2-利用中括号[]查找列表中的字符

grep -n 'm[ey]' testFile.txt # 查找含字符串'me'或'my'的行,如下:
1:God bless me!
2:Oh, my god!
3:What's your name?
7:Time to say goodbye.
grep -n 'm[^ey]' testFile.txt # 查找含m但是后面跟的不是e或y的字符串的行,如下:
9:Gooood morning.
grep -n '[^A-Z]oo' testFile.txt # 查找含oo但前面不是大写字母的字符串的行,如下:
7:Time to say goodbye.
8:Goood evening.
9:Gooood morning.

上例中的第8-9行是因为oo前面跟的是o,未必是G,所以不能排除掉。

例3-行首字符^和行尾字符$

grep -n '^G' testFile.txt # 查找行首G开头的行,如下:
1:God bless me!
6:Goodbye.
8:Goood evening.
9:Gooood morning.
grep -n '!$' testFile.txt # 查找行尾!结束的行,如下:
1:God bless me!
2:Oh, my god!
4:Happy new year!
grep -n '^[OW]' testFile.txt # 行首用O或W打头,如下:
2:Oh, my god!
3:What's your name?
grep -n '^$' testFile.txt # ^$连用表示行首接着行尾,即空白行,如下:
5:
grep -v '^$' testFile.txt | grep -v '^#' # 这个用的较多,把bash脚本中空白行和#开头的注释行都刨掉

例4-任意1个字符. 和 0个到无穷个前面字符的重复*

grep -n 'g..d' testFile.txt # 查找g开头d结尾中间俩任意字符的字符串,如下:
7:Time to say goodbye.
grep -n 'ooo*' testFile.txt # 查找含两个o以上的字符串,要写3个o才行的,如下:
6:Goodbye.
7:Time to say goodbye.
8:Goood evening.
9:Gooood morning.

例5-限定连续字符范围{}(用\转义,故写作{})

grep -n 'o\{2\}' testFile.txt # 查找含2个连续o的字符串,如下:
6:Goodbye.
7:Time to say goodbye.
8:Goood evening.
9:Gooood morning.
grep -n 'o\{3,5\}' testFile.txt # 查找含3-5个连续o的字符串,如下:
8:Goood evening.
9:Gooood morning.
grep -n 'o\{4,\}' testFile.txt # 查找含4个及以上连续o的字符串,如下:
9:Gooood morning.

2.5 sed工具

sed本身是一个管道命令,其可以分析standard input的,而且sed还可以将数据进行替换、删除、新增、选取特定行等的功能。

用法:
sed [-nefr] [动作] fileName

选项:
-n 使用安静模式,一般sed使用时,所有来自stdin的数据都会输出到屏幕上,但是用了安静模式后,只有经过sed处理的特殊行才会被列出来。注意这个-n不是加行号,而是安静模式,悄没声滴,啥也不显摆。
-e 直接在命令行模式上进行sed的动作编辑(默认就是-e的,所以不用添加)。
-f 直接将sed的动作写在一个文件内,-f filename则可以执行filename内的sed动作(相当于把sed的动作写到文件里,然后执行该文件就可以了,好像用不着这么麻烦哈)。
-r sed的动作支持的是扩展正则表达式的语法(默认是基础正则表达式的语法)。
-i 直接修改读取的文件内容,而不是由屏幕输出(默认是不修改源文件,只显示在命令行界面里的,要想修改源文件需要用-i选项)。

动作说明:[n1[,n2]]function
n1, n2 不一定存在,一般代表动作执行的行数,例如,若动作需要在10-20行之间进行,则“10,20[动作行为]”

function有下面参数可选:
a 新增,a的后面可以接字符串,这些字符串会在新的一行出现(当前行的下一行
c 替换,c的后面可以接字符串,这些字符串将替换n1-n2之间的行
d 删除,后面不用接任何参数,因为直接删掉了
i 插入,后面可以接字符串,而这些字符串会在新的一行出现(当前行的上一行
p 打印,将某个选择的数据打印出来,通常p会和参数sed -n一起运行(不然它会把源文件打印出来,再打印选择的数据,比较烦人)
s 替换,可以直接替换的工作。通常s会搭配正则表达式,例如:1,20s/old/new/g

还以前面的测试文件testFile.txt为例来做说明,文件内容如下:

God bless me!
Oh, my god!
What's your name?
Happy new year!

Goodbye.
Time to say goodbye.
Goood evening.
Gooood morning.

例1-删除指定行:

sed '2,8d' testFile.txt	# 删除testFile.txt的2-8行之后再显示,如下:
God bless me!
Gooood morning.
sed -n '2,8d' testFile.txt # 如果想显示行号,不能用-n,-n是安静模式,加上就啥也不输出了。
cat -n testFile.txt | sed '2,8d' # 如果想显示行号,可以用管道符来整,如下:
     1	God bless me!
     9	Gooood morning.

例2-新增行

cat -n testFile.txt | sed '3a Hello World!' # 在第3行后面增加一行‘Hello World!’,如下:
     1	God bless me!
     2	Oh, my god!
     3	What's your name?
Hello World!
     4	Happy new year!
     5	
     6	Goodbye.
     7	Time to say goodbye.
     8	Goood evening.
     9	Gooood morning.
cat -n testFile.txt | sed '3i Hello World!' # 在第3行前面增加一行‘Hello World!’,如下:
     1	God bless me!
     2	Oh, my god!
Hello World!
     3	What's your name?
     4	Happy new year!
     5	
     6	Goodbye.
     7	Time to say goodbye.
     8	Goood evening.
     9	Gooood morning.

如果要增加多行,用反斜杠然后回车就可以换行了(相当于把回车符转义了):

cat -n testFile.txt | sed '3a Hello World! \
> Nice to meet you!'	# 回车后显示如下:
     1	God bless me!
     2	Oh, my god!
     3	What's your name?
Hello World! 
Nice to meet you!
     4	Happy new year!
     5	
     6	Goodbye.
     7	Time to say goodbye.
     8	Goood evening.
     9	Gooood morning.

例3-替换行:

cat -n testFile.txt | sed '2,8c Delete 2-8 lines.' # 将2-8行替换为Delete 2-8 lines.
     1	God bless me!
Delete 2-8 lines.
     9	Gooood morning.

例4-只打印想要的行:
注意,加了-n安静模式,不然的话,下面的打印会依照1,2,3,3,4,4,5,6,7,8,9行的顺序打印一遍。

cat -n testFile.txt | sed -n '3,4p' # 只显示3-4行内容,如下:
     3	What's your name?
     4	Happy new year!

例5-查找替换:
sed ‘s/旧字符串/新字符串/g’

cat -n testFile.txt | sed 's/oooo*/oo/g' # 把三个及以上连续o的字符串替换成两个连续o,如下:
     1	God bless me!
     2	Oh, my god!
     3	What's your name?
     4	Happy new year!
     5	
     6	Goodbye.
     7	Time to say goodbye.
     8	Good evening.
     9	Good morning.

例6-直接修改源文件:
默认的sed操作只是显示在屏幕上,不针对源文件,但是如果想直接修改源文件的话,那么加上-i选项就可以了。

sed 's/oooo*/oo/g' testFile.txt # 把大于等于3个连续o的字符串替换成oo,直接修改源文件,无任何显示!
cat testFile.txt	# 查看源文件,发现的确被更改了,如下:
God bless me!
Oh, my god!
What's your name?
Happy new year!

Goodbye.
Time to say goodbye.
Good evening.
Good morning.

例7-执行文件中写好的sed动作:
用-f可以把事先写好的sed动作拿来执行,比如先新建个文件sedCom,用vi编辑其内容为/s/ me/ you/g,即sed的替换动作,注意不要加单引号,然后sed -f sedCom执行就可以了。

cat -n testFile.txt | sed -f sedCom # 用文件来制定sed动作,执行结果如下,成功替换:
     1	God bless you!
     2	Oh, my god!
     3	What's your name?
     4	Happy new year!
     5	
     6	Goodbye.
     7	Time to say goodbye.
     8	Good evening.
     9	Good morning.

3 扩展正则表达式

用grep命令的时候,如果要同时刨掉空白行和以#开始的注释行,用基础表达式的话,只能写成如下形式:

grep -v '^$' fileName | grep -v '^#'

如果用扩展表达式,就方便多了,注意grep默认只支持基础正则表达式,若想使用扩展正则表达式,需要加上-E选项,即grep -E或者直接用egrep命令就好了。

grep -Ev '^$|^#' fileName
egrep '^$|^#' fileName 

上面单引号里的竖杠杠 | 表示 逻辑或 的意思,属于扩展正则表达式。

扩展正则表达式特殊字符归纳表(假设文件为fileName.txt)

符号意义范例
+重复1个或1个以上的前一个字符可以是god、good、goood等,但非gdegrep -n ‘go+d’ fileName.txt
?0个或1个前一个字符可以是gd、god,但非good、goood等egrep -n ‘go?d’ fileName.txt
|用或or的方式找出多个字符串可以是gd、god、goodegrep -n 'gd
()找出‘组’字符串可以是glad、good,la和oo竖杠隔开egrep -n ‘g(la|oo)d’ fileName.txt
()+多个重复组的判别可以为ILoveLoveLoveU,Love重复多次egrep -n ‘I(Love)+U’ fileName.txt

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

4.1 格式化打印printf

用法:
printf ‘打印格式’ 实际内容
参数:
关于格式方面的几个特殊样式
\a 输出警告声音
\b 退格键backspace
\f 清除屏幕form feed换页符
\n 输出新的一行
\r 回车键Enter
\t 水平tab键
\v 垂直tab键
\xNN NN为两位的数字,可以转化数字为字符
关于c语言内,常见的变量格式
%ns n为数字,s代表字符string,即n位字符串
%ni n为数字,i为整形integer,即n位的整数
%N.nf n和N都是数字,f代表浮点floating,如果有小数数字,总共10位,小数点后保留两位输出,则写成%10.2f就可以了

例,假设有个成绩单文件score,内容如下:

Name English Chinese Math Total Aver
MeiGuanhua 99 98 95 292 97.33
LiLi 88 86 82 256 85.33

让其做格式输出

printf '%s\t %s\t %s\t %s\t %s\t %s\t \n' $(cat score) # 显示如下:
Name	 English	 Chinese	 Math	 Total	 Aver	 
MeiGuanhua	 99	 98	 95	 292	 97.33	 
LiLi	 88	 86	 82	 256	 85.33	

tab的对齐压根就没对齐,而且平均分我只想看1位小数,所以还要处理下才好

printf '%12s %8s %8s %8s %8s %8s \n' $(cat score | sed -n '1p'); \
printf '%12s %8i %8i %8i %8i %8.1f \n' $(cat score | sed -n '2,3p') # 如下:
        Name  English  Chinese     Math    Total     Aver 
  MeiGuanhua       99       98       95      292     97.3 
        LiLi       88       86       82      256     85.3 

4.2 数据处理工具awk

用法:
awk ‘条件类型 1{动作 1} 条件类型 2{动作 2} …’ filename

awk是一列一列来折腾的,默认的分隔符是空格或tab,注意其会把连续的空格算成是一个空格,这点跟之前的cut很不一样,awk人性化多了。

例,还是上面的成绩单文件,但是我只想看到姓名和总成绩的栏,就可以用awk来处理了:

awk '{print $1 "\t" $5}' score
Name	Total
MeiGuanhua	292
LiLi	256

上例将awk和print(注意是print不是printf)联合使用来输出特定分隔的字符串,字符串默认是用空格(连续空格)或tab来分隔的,其中的$1、$2、$3……分别表示第1、第2、第3……个字符串,还有个$0表示这一行所有的字符串。

由于awk的后续动作是要用单引号括起来的,所以如果用print(不是printf)命令的话,如果要打印不是变量的字符或者格式的话,用双引号括起来就好了,比如上例的"\t"。

awk命令中还有3个内置变量,NF、NR、FS分别表示每一行($0)拥有的字段总数、当前awk处理的是第几行、当前的分隔字符(默认是空格键)。

例-输出NF、NR、FS看看:

awk '{print $5 "\t current line: " NR "\t total colume: " NF, "division char:", FS, "."}' score # 显示如下:
Total	current line: 1	 	total colume: 6 division char:   .
292	 	current line: 2	 	total colume: 6 division char:   .
256	 	current line: 3	 	total colume: 6 division char:   .

awk的逻辑运算符

符号意义
>大于
<小于
>=大于或等于
<=小于或等于
==等于
!=不等于

例-看看语文分数大于等于90分的是谁:

awk '$3>=90 {print $1 "\t" $3}' score	# 如下:
Name	Chinese
MeiGuanhua	98

之所以第一行Chinese也输出来了,是因为它把字符串跟90作比较了,不然要输出小于90的,它就不输出第1行了。

当然,如果用printf的话,可以在双引号里面用%s、%i、%f来指明输出类型了。

awk '$3>90 {printf "%10s %10s\n", $1, $3}' score # 显示如下
      Name    Chinese
MeiGuanhua         98
  • awk的动作,即{}内的动作,如果需要用到多个命令,可以用分号把它们间隔开来;
  • 格式化输出时,用printf的情况下,必须要加上\n,不然没法分行;
  • printf的格式与内容需要用逗号隔开才行;
  • awk还支持if条件,不再举例。

4.3 文件比较工具diff、cmp、patch

diff用于两个文件的比较,其以行为单位进行比较,通常用在同一文件(或软件)的新旧版本的区别上!
用法:
diff [-bBi] from-file to-file
其中from-file为欲比较的文件,而to-file为目标比较文件。
参数:
-b 忽略一行中仅有多个空白的区别
-B 忽略空白行的区别
-i 忽略大小写的区别

cmp是比较俩文件的“字节”,当然也可以比较二进制文件。
用法:
cmp [-s] file1 file2
参数:
-s 将所有的不同点的字节都列出来,因为cmp默认仅会输出第1个发现的不同点。

patch与diff密切相关,其常用于比较新旧两个文件,然后制作补丁文件,将旧文件升级为新文件。

4.4 文件打印准备pr

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值