我觉得从0开始学习shell编程最好的一本书就是《UNIX shell范例精解》(英文名UNIX Shells by Example)。这本书从一开始先是讲解进程和shell的基本概念,让你有一个大图景,这样后面学细节就不会浑浑噩噩。
学习正则表达式这一章,我坚持把每一种元字符都在自己机器上实践一下,这样才会印象深刻。不过这只能让自己掌握基础,更多的组合元字符的应用,则要靠长久的实践,因为:运用之妙,存乎一心。
基本概念:
正则表达式是一种字符模式,用于在查找过程中匹配指定的字符。
正则表达式一般放在两个正斜杠之间,比如/will/这个正则表达式将查找任何匹配这个表达式的行。
不过/will/这个表达式并不是一个高大上的表达式,只是一个最简单的查找表达式,即使你不懂正则表达式,估计也用这个在vi里查找过各种字符。
正则表达式的真正威力是:可以用特殊的元字符去控制它们。至于何为元字符,稍后说明。
先看一个最简单正则表达式的应用:
如下文件中,你使用了will,但是你发现语法有问题,想把文中的will全部改成would:
---- clip----
[root@localhost ~]# vi kkkk.txt
Iwilldo that
youwill do that if you didn't
youWilldo
haha, hewill not do that if I didn't
:1,$s/will/would/
[root@localhost ~]# vi kkkk.txt
Iwould do that
youwould do that if you didn't
youWilldo
haha, hewould not do that if I didn't
---- clip----
这个正则表达式中查找串是will,替换串是would,“1,$”表示从文件第一行到文件末尾用would替换所有will。
但这里有一个问题,还有一个你不小心写成大写开头的Will没有被替换掉,这时就得用到我们说的元字符了。
正则表达式元字符:
即使不知道正则表达式,操作过linux的一般都用过这条命令:
[root@localhost travel_life]# rm -rf*.txt
这个里面的*是个通配符,也就是一个shell元字符,也就是说shell会将其解析为”匹配当前工作目录下的所有文件名”。
所以元字符是这样一类字符,它本身并不表达自己字面的意思,比如上面的*.txt,并不是说有个文件名就叫*.txt,而是表示所有后缀为.txt的文件。
正则表达式元字符,则是由各种执行模式匹配操作程序来解析,比如vi、grep、sed、awk等等。
正则表达式元字符是一类特殊字符,可以通过它们以某种方式界定模式,从而控制进行哪些替换。
可以使用元字符来定位在行首或行尾出现的单词,也可以用元字符指定任意字符和某一组字符,从而实现同时查找大写或小写字符(我们上面那个will例子),或者只查找数字等等。
那我们现在来解决上面那个问题:
---clip---
[root@localhost travel_life]# vi kkkk.txt
will do that
you will do that if you didn't
you Will do
haha, he Would not do that if I didn't
:1,$s/[Ww]ill/would/
[root@localhost ~]# vi kkkk.txt
I would do that
you would do that if you didn't
you would do
haha, he would not do that if I didn't
----clip---
这里[Ww]是匹配方括号里的任一字符。
正则表达式元字符表 | |||
元字符 | 功能 | 示例 | 说明 |
^ | 行首定位符 | /^less/ | 匹配所有以less开头的行 |
$ | 行尾定位符 | /less$/ | 匹配所有以less结尾的行 |
. | 匹配单个字符 | /l..s/ | 匹配包含一个l,后跟2个字符,再跟一个s 的行 |
* | 匹配0个或多个位于* | /a*less/ | 匹配包含0或多个a后,跟一个less的行.这种 情况哪怕是mless也能被匹配 |
[] | 匹配一组字符中的任一个 | /[Llt]ess/ | 匹配包含Less或less过tess的行 |
[x-y] | 匹配指定范围内的一个字符 | /[a-z]ess/ | 匹配后面跟着ess的一个a-z之间的字符 |
[^] | ‘非’的意思,匹配不在指定组内的字符 | /[^a-z]/ | 匹配范围不在a-z之间的任意一个字符 |
\ | 转义元字符 | /less\*/ | 匹配包含less之后跟一个*号的行 |
下面是一些许多使用正则表达式元字符的UNITX/Linux程序都支持的附加元字符 | |||
\< | 词首定位符 | /\<less/ | 匹配包含以less开头的词的行(vi和grep都支持) |
\> | 词尾定位符 | /less\>/ | 匹配包含以less结尾的词的行(vi和grep都支持) |
\(…)\ | 匹配稍后将要使用的字符的标签 | /\(less\)er/\1on/ | 最多可以使用9个标签,模式中最左边的是第一个标签,用\1表示.这里左边的模式less被保存为\1,之后凡是出现\1的地方实际上就是less,所以整个表达式就是:lesserlesson(sed,vi和grep都支持) |
x\{m\}或 | 字符x的重复出现: | /k\{7,9\}/ | 匹配包含 7到9个连续的k字符的行(vi和grep 都支持) |
现在我们来对照这个表格一一实践每一个元字符:
1.行首定位符:
------clip-------
[root@localhost travel_life]# vi a.txt
there is a lesserlesson
where is aaless
here is tess
therefore is
there is c mess
/^there/
------clip-------
这里,凡是行首包含了there的都会被查找。
2.行尾定位符:
------clip-------
[root@localhost travel_life]# vi a.txt
there is alesserlesson
where is aaless
here is tess
therefore is
there is cmesson
/sson$/
------clip-------
这里,凡是行尾出现sson的都会被查找。
3.匹配单个字符:
------clip-------
[root@localhost travel_life]# vi a.txt
there is alesserlesson
where is aalxss
here is tess
therefore is
/l.ss/
------clip-------
这里,凡是l和ss之间有任意字符的都会被查找。
4.匹配0个或多个位于*之前的字符:
------clip-------
[root@localhost travel_life]# vi a.txt
there islesserlesson
where islss
here is tless
therefore 1leeess
is l3ss
/le*ss/
------clip-------
这里,凡是l后面跟0到多个e然后再跟ss的行都会被查找。
5.匹配一组字符中的任一个(见上面would取代will/Will的例子)
6.匹配指定范围内的一个字符:
------clip-------
[root@localhost travel_life]# vi a.txt
there islesson
where is lss
here is tlMss
therefore 1leeess
isl3ss
/l[0-9a-z]ss/
------clip-------
这里,凡是l后面跟一个数字或小写字母,然后跟ss的行都会被查找。
7.匹配不在指定组内的字符:
------clip-------
[root@localhost travel_life]# vi a.txt
there is lesson
where is lss
here istlMss
this l*ss
therefore 1leeess
is l3ss
/l[^0-9a-z]ss/
------clip-------
这里,凡是l后面跟一个非数字也非小写字母的字符,然后跟ss的行都会被查找
8.转义元字符:
------clip-------
[root@localhost travel_life]# vi a.txt
there is lesson
where is lss
here is tlMss
this l*ss
therefore 1leeess
is l3ss
/l\*ss/
------clip-------
9.词首词尾定位符:
------clip-------
[root@localhost travel_life]# vi a.txt
there islesson
where islessa
here is xtless
thisless
therefore 1leeess
is l3ss
/\<less/
[root@localhost travel_life]# vi a.txt
there is lesson
where is lessa
here isxtless
thisless
therefore 1leeess
is l3ss
/less\>/
------clip-------
10.匹配稍后将要使用的字符的标签
在如下文件a.txt中,你发现”政府(government)”这个单词你漏掉了一个n而误写成了govement,于是先通过查找,然后再将其修改过来:
------clip-------
[root@localhost travel_life]# vi a.txt
Thegovermentis so corrupt
Thegovermentallounced that people
govermentpolice
aaaand soooo oooon
:1,$s/\(gover\)ment/\1nment/
[root@localhost travel_life]# vi a.txt
The government is so corrupt
The government allounced that people
government police
aaaand soooo oooon
------clip-------
11.匹配重复出现多次的字符
------clip-------
[root@localhost travel_life]# vi a.txt
yourlook lookgood
yourlooklooklike a goose
but you can't eatfood like agoose
if you don't agree me, pleasegooooogle it
/o\{2,7\}/
------clip-------