对于刚接触的人而言,正则表达式的学习与使用一个痛苦而迷茫的东东,但是只要有热心,也会发现很有趣的。那么请让我们打起精神,拿出自己的兴趣与激情一起走进Linux的奇妙世界吧。
什么是正则表达式?
正则表达式是你定义的,Linux工具用来过滤文本的模式模板,换句话说就是使用一定的工具(比如今天要写的grep和egrep)用来文本匹配和过滤的一个手段,是通过正则表达式引擎来实现的,而正则表达式引擎是解释正则表达式模式并使用这些模式进行文本匹配的底层软件,在Linux中有两种流行的正则表达式引擎(也就有两种正则表达式分别是基本正则表达式和扩展正则表达式):
(1)POSIX基本正则表达式式(BRE)引擎
(2)POSIX扩展正则表达式(ERE)引擎
什么是grep和egrep?
上面已经提到了正则表达式的文本匹配和过滤需要使用工具来实现的,而grep和egrep就是其中的两个(其实grep -E就相当于egrep,因此也可以当一个来使用)工具。
基本正则表达式:
字符匹配:
.:代表匹配任意单个字符。注意一定是单个字符,例如ab.匹配的是三个字符。
[]:表示匹配“[]”里面包含的任意字符,与通配符相似(相似的原因是通配符不区分大小写而正则表达式是严格区分大小写的)也可以用“-”连接一个来匹配一个范围中的任意字符,例如“[0-9]”表示0到9之间且包含0和9的任意单个数字,"[a-z]"表示小写字母,“[A-Z]”表示大写字母。
[[:alpha:]]:表示匹配任意一个字母,相当于[a-zA-Z]。
[[:upper:]]:表示匹配任意一个大写字母,相当于[A-Z].
[[:lower:]]:表示匹配任意一个小写字母,相当于[a-z]。
[[:digit:]]:表示匹配任意一个数字,相当于[0-9]。
[[:alnum:]]:表示匹配任意文字数字,注意不包括空白等特殊字符,相当于[[:alpha:][:digit:]],也相当于[0-9a-zA-Z]
[[:punct:]]:表示匹配任意一个标点符号。
[[:space:]]:表示匹配任意一个空白字符(包括空格,空行,制表符)。
[[:graph:]]:表示匹配任意非空字符(非空格,控制字符)。
[[:contrl:]]: 表示匹配任意一个控制字符(就是Ctrl+key)。
[[:print:]]:表示匹配任意一个非空字符(包括空格)。
[[:xdigit:]]:表示匹配任意一个16进制数字.
注意:因为写的是[]的类容所以我在外面都加了[]
[^]:表示匹配除了[]中的其他任意单个字符,注意[]中的字符不包含在最前面的^(因为^只有出现在最前面才有特殊意义);例如[^^]表示除了^之外的任意单个字符,其他的只需要在其前面加上^就行了例如[^[:alpha:]]表示匹配非字母的任意单个字符。重要的话说三遍:我只是为了写[]的内容所以都在最外面加上了[]。因此事实上[:alpha:]代表字符!!!!!
*:代表匹配其前面的字符n次,注意可以是零次比如ab*c可以是包含ac,abc,abbc的任意字符串(之所以是“包含”是因为正则表达式的贪婪模式,它会匹配出所匹配到的包含所有你给出的模式)因此上面的例子中aacc也匹配。
+:代表匹配其前面的字符出现至少一次或者n次,注意这里其前面的字符不能没有,例如
?:代表匹配其前面的 字符出现至少0次至多一次
\{m\}:代表匹配其前面字符出现m次,注意必须一定得是m次
\{m,n\}:代表匹配其前面字符出现至少m次,至多n次
\{m,\}:代表匹配其前面字符出现至少一次,至多不限
\{,n\}:代表匹配其前面字符至多出现一次,至少不限,可以是0次
位置锚定:
^:表示行首锚定,必须用在模式的最左侧才是行首锚定,否则失效
$:表示行尾锚定,必须出现在模式的最右侧才是行尾锚定,否则失效
注意:这表示的是行的锚定,是整个行!!!单个使用的时候只能匹配与模式相同的行首或行位,要想同时锚定行首和行位必须两个一起用上。例如下面两个看起来特别一点的:
^$:代表空白行
^[[:space:]]*$:代表空白行或者包含空白字符行
\<或者\b:表示词首锚定 ,必须出现在想要锚定的单词的侧!!!
\ >或者\b:表示词尾锚定,必须出现在想要锚定的单词的右侧!!!
注意:这两个单独使用的时候不是匹配完整单词的意思,要想匹配完整单词就两个同时用上\<单词模式\>
分组与引用:当想要匹配一个模式多次出现的时候最好的方法就是将其分组,然后在后面加以引用,就是“(匹配模式)”当然匹配模式中也可以有分组,即分组的嵌套,但是不管如何嵌套我们的正则表达式引擎都会按次序将最外面的“(匹配模式)”所匹配到的内容存在1中,从外到里,依次类推,分别是234。。。。n(这里一定要注意是其匹配到的内容,而不是模式本身),然后引用的时候只需要1234.。。。n就可以了:
(匹配模式):匹配模式中还可以有匹配模式,一定要注意了。
扩展正则表达式(这里我只在与基本正则表达式不一样的后面加以解释,你懂的“不要重复造轮子”):
字符匹配(与基本正则表达式用法和意义一样):
.:
[]:
[^]:
匹配次数:
*:与基本正则表达式用法意义一样
+:在扩展的正则表达式中“+”不需要转义,与基本正则表达式意义一样
?:同样“?”也不需要转义,与基本正则表达式意义一样
{m}:同样,“{” 与 “}”也不需要转义,与基本正则表达式意义一样
{m,n}
{,n}
{m,}
位置锚定(与基本正则表达式用法意义一样):
^
$
\<或者\b
\>或者\b
分组与引用:
(匹配模式):不需要转义,其他引用方法与意义与正则表达式一样
或(这是扩展正则表达式特有的):
|:匹配左边的或者右边的,需要注意的是其左边指的是左边的全部内容,右边指的是右边的全部内容
例如:“like|r”表示匹配“like”或者“r”
好了,正则表达式基本元字符与意义写完了,记住多敲键盘多练,只学不练一场空啊!那么现在就来写写支持使用正则表达式的两个工具grep和egrep(只有木头没有电动锯不行啊)。
什么是grep和egrep?
grep和egrep是文本搜索工具,并将匹配到的匹配到的内容打印出来,grep不带选项代表只支持基本正则表达式,代理“-E”表示支持扩展正则表达式,egrep默认支持扩展正则表达式与“grep -E”意义一样。
grep命令用法:
grep [选项] 匹配模式 文件
常用选项:
-e:可以同时使用多个匹配模式,例如:grep -e ‘匹配模式1’ -e ‘匹配模式2’
。。。 文件
-f 写了匹配模式的文件(scripfile):表示从scripfile中提取匹配模式来匹配文件
-q:静默模式,无论匹配成功与否都不将类容打印出来
--color=auto:将匹配到的模式高亮显示出来
-o:仅输出匹配到的模式本身
-E:支持扩展正则表达式
-i:不区分匹配模式中的大小写
egrep命令用法:
-e,-f,-q,--color=auto,-v,-o,-i,-A #,-b#,-c#:与grep意义一样
-G:支持基本正则表达式,相当于grep。
例题:
1,显示出/etc/passwd下含有root的行。
[root@localhost/]#grep"root"/etc/passwd root:x:0:0:root:/root:/bin/bash operator:x:11:0:operator:/root:/sbin/nologin
2,显示出/etc/passwd中不以bash结尾的行。
[root@localhost/]#grep-v"bash$"/etc/passwd bin:x:1:1:bin:/bin:/sbin/nologin daemon:x:2:2:daemon:/sbin:/sbin/nologin adm:x:3:4:adm:/var/adm:/sbin/nologin lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
3,找出/etc/passwd下3位或4位数的行。
[root@localhost/]#cat/etc/passwd|grep"\<[0-9]\{3,4\}\>" games:x:12:100:games:/usr/games:/sbin/nologin avahi-autoipd:x:170:170:AvahiIPv4LLStack:/var/lib/avahi-autoipd:/sbin/nologin systemd-bus-proxy:x:999:997:systemdBusProxy:/:/sbin/nologin systemd-network:x:998:996:systemdNetworkManagement:/:/sbin/nologin polkitd:x:997:995:Userforpolkitd:/:/sbin/nologin mageedu:x:1000:1000:mageedu:/home/mageedu:/bin/bash
4,找出/etc/grub2.cfg下的以至少一个空白字符开头后跟非空白字符的行。
[root@localhost/]#cat/etc/grub2.cfg|grep"^[[:space:]]\+[^[:space:]]" load_env setdefault="${next_entry}" setnext_entry= save_envnext_entry setboot_once=true setdefault="${saved_entry}" menuentry_id_option="--id"
因为是基本正则表达式,所以+需要转义,当然也可以在grep后带上-E然后加好就不需要转义 了。
5,echo一个绝对路径,然后用grep取其基名。
[root@localhost/]#echo"/etc/sysconfig/network-script"|egrep-o"[^/]+/?$" network-script
注意:因为^是锚定行首的,所以如果不用中括号的好就会将后面的所有字符都锚定。
6,仅显示出/etc/passwd中含有root。
[root@localhost/]#cat/etc/passwd|grep-o"root" root root root root
7,显示/etc/passwd中含有至少两个root的行。
[root@localhost /]# cat /etc/passwd | grep -E ".*(root).*\1"
root:x:0:0:root:/root:/bin/bash
[root@localhost /]# cat /etc/passwd | grep -E "(root).*\1"
root:x:0:0:root:/root:/bin/bash
[root@localhost /]# cat /etc/passwd | grep -E "(root).*\1.*"
root:x:0:0:root:/root:/bin/bash
[root@localhost /]# cat /etc/passwd | grep -E ".*(root).*\1.*"
root:x:0:0:root:/root:/bin/bash
之所以会这样的原因是因为其贪婪模式。
[root@localhost etc]# ls | sed "s:^:`pwd`/:"
/etc/adjtime /etc/aliase /etc/aliases.db /etc/alternatives
因为^是锚定句首的,所以这样用就可以使得ls恢复其原本的每行显示的功能,然后命令引用。
那么$,\<.\>.\b.\b.也可以。
总结:
正则表达式最主要的是灵活,特别的是锚定的元字符,注意锚定行的元字符和锚定单词的元
字符的混合使用。还有就是分组与引用的原理过程一定要清楚。这里只是列出了几个简单的
例子,仅仅是演示作用,更多的还是需要灵活。