正则表达式
正则表达式是处理字符串的一种表示方式,需要额外的支持工具来辅助在这里我们使用grep。另外,不同的语系对正则表达式的输出会有不同的影响效果。举例来说,在英文大小写的编码顺序中,zh_CN.big5 与 C 两种语系的输出结果分别如下:
LANG = C 时: 0 1 2 3 4 ... A B C D ... Z a b c d ... z LANG = zh_CN 时: 0 1 2 3 4 ... a A b B c C d D ... z Z
因此,在使用正则表达式时,要特别留意当时环境与语系,否则就会发现与别人不相同的选取结果。
在这里,我们使用的是兼容POSIX标准,因此使用C语系,下面列出一部分常用的特殊符号:
[:alnum:] 代表英文大小写字符及数字,即0-9,A-Z,a-z [:alpha:] 代表任何英文大小写字符,即A-Z,a-z [:blank:] 代表空格键与[Tab]按键 [:cntrl:] 代表键盘上的控制按键,即包括CR, LF, Tab, Del等 [:digit:] 代表数字 [:graph:] 除了空格键(空格键与[Tab]按键)之外的其他按键 [:lower:] 代表小写字符 [:print:] 代表任何可以被打印出来的字符 [:punct:] 代表标点符号(punctuation symbol),即" ' ? ! ; . , # $ [:upper:] 代表大写字符 [space::] 任何会产生空白的字符 [:xdigit:] 代表十六进制的数字类型,因此包括0-9, A-F, a-f的数字与字符
其中常用的有[:alnum:], [:alpha:], [:upper:], [:lower:], [:digit:]等,要牢记~!
grep的一些高级参数。grep是一个很常见也很常用的命令,最重要的功能就是进行字符串额对比,然后将符合用户要求的字符串打印出来。需要说明的是grep在数据中查找一个字符串时,是以整行为单位来进行数据的选取的。
$ grep [-A] [-B] [--color=auto] '搜寻字符串' filename 参数: -A: 后面可加数字,为after的意思,指除了列出该行外,后续的n行也列出来; -B: 后面可加数字,为before的意思,指除了列出该行外,前面的n行也列出来; --color=auto 可将正确选取的那个数据列出颜色 范例: 1)用dmesg列出内核信息,再议grep找出内含eth的那行 $ dmesg | grep 'eth' 2) 承上,将找到的关键字显色,且加上行号来显示 $ dmesg | grep -n --color= auto 'eth' 3) 承上,在关键字所在行的前两行和后三行也显示出来 $ dmesg | grep -n -A3 -B2 --color=auto 'eth'
为了简化下面的使用,用alias命令使grep表示grep --color=auto,命令如下: alias grep='grep --color=auto'. 下面进行基础正则表达式的练习。我们使用的是样例来自:http://linux.vbird.org/linux_basic/0330regularex/regular_express.txt
查找特定字符串
-
$ grep -n 'the' regular.txt 结果显示如下: 12:I can't finish the test. 16:the symbol '*' is represented as start. 19:You are the best is mean you are the no. 1. 20:The world <Happy> is the same with "glad". 22:google is the best tools for search keyword. 若想反向选择?当该行没有'the'字符串时才会显示在屏幕上。那么,使用: $ grep -vn 'the' regular.txt 若想要取得不论大小写的‘the’字符串,使用如下命令: $ grep -in 'the' regular.txt 结果显示如下: 12:I can't finish the test. 13:Oh! The soup taste good. 16:the symbol '*' is represented as start. 18:The gd software is a library for drafting programs. 19:You are the best is mean you are no. 1.
20:The world <Happy> is the same with "glad". 22:google is the best tools for search keyword.
- 利用中括号[]来查找集合字符
-
若想查找test或taste这两个单词,可以发现他们有共同的 't?st'存在,因此我们可以这样查找: $ grep -n 't[ea]st' regular.txt 结果显示如下: 1:This file is a test file. 12:I can't finish the test. 13:Oh! The soup taste good. 其实不管[]里面有几个字符,它都只代表一个字符。又如,想查找有 oo 的字符串时,使用: $ grep -n 'oo' regular.txt 结果显示如下: 5:"Open Source" is a good mechanism to develop programs. 6:apple is my favorite food. 7:Football game is not use feet only. 13:Oh! The soup taste good. 22:google is the best tools for search keyword. 23:goooooogle yes! 但是,如果不想要 oo 前面有 g 的话的?此时,可以利用集合字符的反向选择 [^] 实现: $ grep -n '[^g]oo' regular.txt 结果显示如下: 6:apple is my favorite food. 7:Football game is not use feet only. 22:google is the best tools for search keyword. 23:goooooogle yes! 注意,第23行也显示出来,是因为go(oooo)ogle,可以认为前后都是o,因此也显示出来了。再来,假设我们oo前面不想有小写字符,我们可以这样写[^abcd...z]oo,但这样似乎太不方便,而由于小写字符的ASCII码是连续的,因此我们可以这样简化: $ grep -n '[^a-z]00' regular.txt 结果显示如下: 7:Football game is not use feet only. 也就是说,如果我们所选取的字符串是连续的,如大写英文/小写英文/数字时,就可以使用[a-z], [A-Z], [0-9]. 同样地,如果我们的要求字符串是数字或英文呢?就可以将它们全部写在一起 [a-zA-Z0-9]. $ grep -n '[0-9]' regular.txt 考虑到语系对于编码顺序的影响,连续编码除了使用‘-’外,还可以使用我们前面介绍的特殊字符。 $ grep -n '[^[:lower:]]oo' regular.txt 结果显示如下: 4:I am going to my home. 5:"Open Source" is a good mechanism to develop programs. 6:apple is my favorite food. 7:Football game is not use feet only. 8:this dress doesn't fit me. 9:However, this dress is about $ 3183 dollars. .
.
. 24:go! go! Let's go. 25:# I am VBird -
行首与行尾字符^$
-
在上面的例子中,我们得到了包含"the"的字符,但是如果想让the只出现在行首位置呢?这个时候就应该使用制表符了。使用如下命令: $ grep -n '^the' regular.txt 结果显示如下: 16:the symbol '*' is represented as start. 如果我们想要结果开头是小写的那一行出列呢?使用如下命令: $ grep -n '^[a-z]' regular.txt / $grep -n '^[[:lower:]]' regular.txt 结果显示如下: 2:vi is a little difficult. 6:apple is my favorite food. 8:this dress doesn't fit me. 14:motorcycle is cheap than car. 16:the symbol '*' is represented as start. 22:google is the best tools for search keyword. 23:goooooogle yes! 24:go! go! Let's go. 如果不想要开头是英文字母,可以这样写: $ grep -n '^[a-zA-Z]' regular.txt / $grep -n '^[^[:alpha:]]' regular.txt 结果显示如下: 5:"Open Source" is a good mechanism to develop programs. 25:# I am VBird 注意:通过上面的例子我们可以看出,^符号在[]里面与在[]外面是不同的!!!![^...] 是指我们得到的结果中不包含中括号[]的字符(反向选择);而^[]是指定位在行首,表示行首制表符。 如果我们想得到行尾结束为小数点"."的那一行,该如何处理? $ grep -n '\.$' regular.txt 结果显示如下: 4:I am going to my home. 5:"Open Source" is a good mechanism to develop programs. 6:apple is my favorite food. .
.
.
19:You are the best is mean you are the no. 1. 20:The world <Happy> is the same with "glad". 21:I like dog. 22:google is the best tools for search keyword. 24:go! go! Let's go. 特别的是,小数点"."具有其他的意义,因此我们使用转移字符"\"来加以解除其特殊意义. 如果我们想找出哪一行是“空白行”该怎么表示?也就是说该行没有任何输入数据,可以使用如下语句: $ grep -n '^$' regular.txt 解析:因为只有行首跟行尾,因此使用上面的语句就可以找出空白行。
假设你已经知道一个程序脚本(shell script)或者是配置文件中,空白行与#开头的那一行是批注,因此如果你要将数据列出来给别人参考时,可以将这些数据省略掉方便观察,那么该如何实现?看下面这个例子。 $ cat -n /etc/syslog.conf 列出syslog.conf的所有数据显示如下: 1 # Note that flat file logs are now configured in /etc/asl.conf 2 3 install.* @127.0.0.1:32376 用如下命令省略其中的空白行和注释行: $ grep -v '^$' /etc/syslog.conf | grep -v '^#' 结果显示如下: install.* @127.0.0.1:32376 - 任意一个字符.与重复字符*
- 在bash中,我们知道通配符*可以用来表示任意字符(0个或者多个),但是正则表达式并不是通配符~!两者是不同的~!在正则表达式中,"."表示绝对有一个任意字符的意思!这两个字符在正则表达式中的意义如下:
- .(小数点):表示一定有一个任意字符的意思;
- *(星号):表示重复前一个0到无穷多次的意思,为组合形态。
-
比如我们想要找出g??d的字符串,即共有四个字符,开头是g,而结尾是d,可以使用下面的语句: $ grep -n 'g..d' regular.txt 结果显示如下: 5:"Open Source" is a good mechanism to develop programs. 13:Oh! The soup taste good. 20:The world <Happy> is the same with "glad".
$ grep -n 'o*' regular.txt 结果显示如下: 列出了文件中所有的数据。(原因是*表示重复前面的字符0次或无穷多次,因此有可能重复0次,把所有的数据都打印出来) $ grep -n 'oo*' regular.txt 结果显示如下: 将所有只要包含一个o的数据都列出来了。(原因同上。oo*只会保证第一个o一定会出现,因此是哟啊包含一个o的数据都会被列出来) $ grep -n 'ooo*' regular.txt 结果显示如下: 5:"Open Source" is a good mechanism to develop programs. 6:apple is my favorite food. 7:Football game is not use feet only. 13:Oh! The soup taste good. 23:google is the best tools for search keyword. 24:goooooogle yes! 这种情况下才会列出我们想要的数据。(原因是只有前两个oo能够保证显示出来,后面还会跟着0个或者多个o)
-
练习:如果我们想要字符串开头与结尾都是g,但是两个g之间仅能存在至少一个o,即g0g, goog, gooooog等,则应使用如下语句: $ grep -n 'goo*g' regular.txt 结果显示如下: 24:goooooogle yes! 如果我们想找出g开头与g结尾的字符串,中间的字符可有可无,那该如何写? $ grep -n 'g*g' regular.txt 结果显示如下: 4:I am going to my home. 5:"Open Source" is a good mechanism to develop programs. 7:Football game is not use feet only. 13:Oh! The soup taste good. 17:Oh! My god! 18:The gd software is a library for drafting programs. 20:The world <Happy> is the same with "glad". 21:I like dog. 23:google is the best tools for search keyword. 24:goooooogle yes! 25:go! go! Let's go. 如果我们想得到g...g的字符串该如何写表达式呢?使用如下语句: $ grep -n 'g.*g' regular.txt 结果显示如下: 4:I am going to my home. 5:"Open Source" is a good mechanism to develop programs. 18:The gd software is a library for drafting programs. 23:google is the best tools for search keyword. 24:goooooogle yes! 25:go! go! Let's go. 下面,如果我们想得到找出“任意数字”的行列呢? $ grep -n '[0-9][0-9]*' regular.txt / $ grep -n '[[:digit:]][[:digit:]]*' regular.txt 结果显示如下: 9:However, this dress is about $ 3183 dollars. 19:You are the best is mean you are the no. 1.
- 规定连续RE字符范围{}.
- 在上面,我们可以利用.和*来设置0到无穷多个重复字符,那如果我们想要限制一个范围区间内的重复字符呢?比如,我们想得到2~5个o的连续字符串该如何做?此时就应该用到限定范围的字符{}了.但是因为{与}的符号在shell是由特殊意义的,因此,我们必须要使用转义字符\使它失去特殊意义才行。至于{}的语法是这样的,假设我要找两个o的字符串,可以是:
-
$ grep -n 'o\{2\}' regular.txt 结果显示如下: 5:"Open Source" is a good mechanism to develop programs. 6:apple is my favorite food. 7:Football game is not use feet only. 13:Oh! The soup taste good. 23:google is the best tools for search keyword. 24:goooooogle yes!
- 假设我们要找g后面接2到5个o,然后再接一个g的字符串,应该这样写:
-
$ grep -n 'go\{2,5\}g' reguar.txt 结果显示如下: 23:google is the best tools for search keyword.
- 如果我们想要的是2个o以上的gooo..og呢?
-
$grep -n 'gooo*g' regular.txt / $ grep -n 'go\{2,\}g' regular.txt 结果显示为: 23:google is the best tools for search keyword. 24:goooooogle yes!
总结,基础正则表达式字符(characters)
^word |
意义:待查找的字符串在行首。 例:查找#为开头的那一行,并列出行号 grep -n '^#' regular.txt |
word$ |
意义:待查找的字符串在行尾。 例:将行尾为!的那一行打印出来 grep -n '!$' regular.txt |
. |
意义:代表一定有一个任意字符的字符 例:查找的字符串可以是(eve) (eae) (eee) (e e),但不能仅有(ee)! 即e与e之间“一定”仅有一个字符,空格也属于一个字符。 grep -n 'e.e' regular.txt |
\ |
意义:转义字符,将特殊符号的特殊意义去除 例:查找含有单引号'的那一行 grep -n '\'' regular.txt |
* |
意义:重复零个到无穷多个的前一个字符。 例:找出含有(es) (ess) (esss)等得字符串,注意,因为*可以是0个,所以es也是符合条件带查找字符串。另外,因为*为重复前一个RE字符,因此,在*之前必须紧挨着一个RE字符!例如任意字符则为“.*” grep -n 'ess*' regular.txt |
[list] |
意义:从字符集合的RE字符里面找出想要选取的字符 例:查找含有(gl)或(gd)的那一行。注意:在[]中代表一个待查找的字符。如"a[afl]y"代表待查找的字符串可以是aay, afy, aly,即[afl]代表a或f或l的意思 grep -n 'g[ld]' regular.txt |
[n1-n2] |
意义:从字符集合的RE字符里面找出想要选取的字符范围 例:查找含有任意数字的那一行。需要留意的是,[]中的减号-是由特殊含义的,它代表两个字符之间的所有连续字符。但这个连续与否与ASCII编码有关。 grep -n '[0-9]' regular.txt |
[^list] |
意义:从字符集合的RE字符里面找出不要的字符串或者范围 例:查找的字符串可以是(oog) (ood) 但不能是(oot). ^在[]里表示的意义是“反向选择”.例如我不要大写字符,则应写为[^A-Z]. 需要注意的是,若写为grep -n '[^A-Z]', 会发现文件内所有的行都被列出,因为[^A-Z]表示的是“非大写字符”,每一行中都有小写字符。 grep -n 'oo[^t]' regular.txt |
\{n.m\} |
意义:连续n到m得前一个RE字符,若为\{n\}则是连续n个的前一个RE字符,若为\{n,\}则是连续n个以上的前一个RE字符。 例:在g与g之间有2到3个o存在的字符串,即(goog) (gooog) grep -n 'go\{2,3\}g' regular.txt |
特别注意,正则表达式的特殊字符与一般在命令行输入命令的“通配符”并不相同~!举例来说,在不支持正则表达式的ls工具中,若我们使用“ls -|*”代表的是任意文件名的文件,而“ls -la*”代表的是以a为开头的任何文件名的文件,但在正则表达式中,我们要找到含有以a为开头的文件则必须使用以下语句:
ls | grep -n '^a.*'
PS: 以上资料均来源于“鸟哥的Linux私房菜”.