正则表达式与grep
grep与正则表达式
无论是生活、还是学习,想要成为搜索的高手,正则表达式都是绕不过的一道槛,利用正则表达式可以迅速找到我们想要的任何信息。
正则表达式的理解与其说需要时间的沉淀,不如是说是需要思考的沉淀和多次的练习。
当我们学习时正则、扩展正则时不能拘泥于"城池"的得失,要关注大局,学完比学好更重要!
0、grep
DISCRIPTION:
grep:global search regular expression and print out the line(根据正则表达式进行全局搜索并打印输出行)
grep是文本搜索工具,是根据用户指定的模式对目标文本进行匹配检查,并打印匹配到的行,注意是打印匹配文件的所在行,而不是打印匹配到的目标文本。
所谓模式就是由正则表达式及文本字符构成的过滤条件。
SYNOSIS:
grep [OPTIONS] PATTERN [FILE...]
grep [OPTIONS] [-e PATTERN | -f FILE] [FILE...]
默认grep没有语法着色,其语法着色是通过别名
--color=auto
生效的。
OPTIONS:
-i:ignorecase:忽略大小写
-o:仅显示匹配的到的字符串本身
-v:invert-match,显示不能被模式匹配的行
-E: 支持扩展正则,egrep与其等同
-q:--quiet,--slient,静默模式,即不输出任何信息(脚本当中会用到,省了&>/dev/null
)
-A #:after,后#行
-B #:before,前#行
-C #:context,前后各#行
1、基础
特殊字符
-
:代表上一个目录
[root@N2 zhanghe]# cd
[root@N2 ~]# cd $OLDPWD
[root@N2 zhanghe]#
[root@N2 zhanghe]# cd /etc/
[root@N2 etc]# cd -
/root/zhanghe
.
:当前目录
//清空当前目录
[root@N2 zhanghe]# rm -rf ./*
..
:上一级目录
[root@N2 tmp]# cd ..
[root@N2 /]#
~
:家目录,cd默认就是回家目录
[root@N2 zhanghe]# cd ~
[root@N2 ~]#
xargs
,分组,输入重写向,也常与find连用,有将字符流转换为可用路径的含义。
[root@N2 zhanghe]# echo {1..10} > test2.txt
[root@N2 zhanghe]# cat test2.txt
1 2 3 4 5 6 7 8 9 10
//3个一组
[root@N2 zhanghe]# xargs -n 3 <test2.txt
1 2 3
4 5 6
7 8 9
10
引号相关
不加引号可支持通配符,无法将内容变成整体,含义和双引号一样
[root@N2 zhanghe]# touch a b
[root@N2 zhanghe]# touch "a b"
[root@N2 zhanghe]# ll
-rw-r--r-- 1 root root 0 Feb 10 18:28 a
-rw-r--r-- 1 root root 0 Feb 10 18:28 a b
-rw-r--r-- 1 root root 0 Feb 10 18:28 b
单引号:所见即所得
[root@N2 zhanghe]# zh=zhanghe
[root@N2 zhanghe]# echo '$zh'
$zh
双引号:特殊符号会被解析
[root@N2 ~]# zh=zhanghe
[root@N2 ~]# echo '$zh'
$zh
[root@N2 ~]# echo "$zh"
zhanghe
反引号:引用命令,可将字符流转换为路径;等同于$()。
//将字符流转换为生效路径,与xargs意义类似
[root@N2 ~]# mv `find /etc -name *tion` /tmp
[root@N2 ~]# ls /tmp
application motion
//host=$(echo zhanghe)等同于host=`echo zhanghe`
[root@N2 ~]# vim test.sh
#!/bin/bash
host=$(echo zhanghe)
echo $host
[root@N2 ~]# sh test.sh
zhanghe
2、通配符
通配符的作用是帮助我们查找文件名的,常常与
find -name
、ls
连用,这一点要记住,而正则表达式用来找文件内容的。
*
:匹配0或多个字符,看清是0和多个字符,也就是说也可以没有,比如:
//文件名当中只要包含zh即可
[root@N2 zhanghe]# touch hellozh zhhello hezhllo zh
[root@N2 zhanghe]# ls *zh*
hellozh hezhllo zh zhhello
?
:仅代表一个字符。
[root@N2 zhanghe]# touch zhanghe zhangghe zhanggghe
[root@N2 zhanghe]# ls zhang?he
zhangghe
[abcd]
:匹配中括号里面的任意一个字符,看准是一个。
[root@N2 zhanghe]# touch a b c d e f g
[root@N2 zhanghe]# ls [abcd]
a b c d
[a-z]
:[1-9]与之类似,匹配中括号里面的任意一个字符,a-z代表26个小写字母,看准是一个。
[root@N2 zhanghe]# touch a b c d e f g
[root@N2 zhanghe]# ls [a-d]
a b c d
[root@N2 zhanghe]# ls [a-z]
a b c d e f g
[!a-z]
:[!1234]与之类似,!
可用^
代替,匹配取反中括号里面的任意一个字符,[a-d]同理。
[root@N2 zhanghe]# touch a b c d e f g
[root@N2 zhanghe]# ls [!a-d]
e f g
3、正则表达式元字符
字符匹配
.
任意单个字符
[]
:范围内的任意单个字符。
[^] :范围外的任意单个字符。
//匹配以r开头中间必须是两个字符结尾是t的字符串
[root@N2 ~]# grep 'r..t' /etc/passwd
root:x:0:0:root:/root:/bin/bash
operator:x:11:0:operator:/root:/sbin/nologin
ftp:x:14:50:FTP User:/var/ftp:/sbin/nologin
//r..t这个模式中的.包括空格吗?包括,例如:
[root@N2 ~]# cat test.txt
ro t
[root@N2 ~]# grep 'r..t' test.txt #在终端选中结果后,会发现空格也是着色的,说明把空格也匹配了
ro t
常用字符集:
[:digit:]:所有数字
[:lower:]:所有小写字母
[:upper:]:所有大写字母
[:alpha:]:所有字母(包括大小写)
[:alnum:]:所有字母(包括大小写)和数字
[:punct:]:所有标号符号
[:space:]:注意,仅表示一个空格
//匹配r开头中间任意一个小写字母结尾是t的行,注意[:lower:]仅代表字符集,不能单独使用,只有外面再加一个中括号才表示这些字符集里面的一个。
[root@N2 ~]# grep 'r[[:lower:]]t' /etc/passwd
//与上一个例子相似,只不过这是取反
[root@N2 ~]# grep 'r[^[:digit:]]t' /etc/passwd
/匹配/r和t之间有两个字母的行,这样写太麻烦,所以要有次数匹配
[root@N2 ~]# grep 'r[[:alpha:]][[:alpha:]]t' /etc/passwd
次数匹配
用在要指定其出现次数的字符的后面,用于限制其前面字符出现的次数,默认工作于贪婪模式。
*
:匹配其前面的字符任意次,0次、1次 ,2次……,多次。
.*
:匹配任意长度的任意字符
\?
:匹配前面的字符0次或1次,即其前面的字符是可有可无的。
\+
:匹配其前面的字符1次或多次,即其前面的字符要出现至少1次
\{m\}
:匹配其前面的字符m次
\{m,n\}
:匹配其前面的字符至少m次,至多n次
\{0,n\}
:至多n次
\{m,\}
:至少m次
值得说一说的是*:
//表示只要有y出现即可,x可以没有,也可以有任意次
grep 'x*y' test.txt
//任意单个字符,可有可无,而且可以有多次,所以会匹配任意长度的任意字符,包括特殊字符什么的,而且由于其贪婪性,如果对一个文档使用.*的话,里面的所有都会被匹配上,在终端选中后即可验证。
grep '.*' test.txt
位置锚定
位置锚定之行锚定:
^
:行首锚定,写在模式的最左边
$
:行尾锚定,用于模式的最右边
^pattern$
:用pattern来匹配整行
^$
空白行
^[[:space:]]*$
:空行或包含空白字符的行
位置锚定之单词锚定:
这些的单词指是非特殊字符组成的连续字符串都称为单词。
\<或\b
:词首锚定,用于单词模式的左侧
\>或\b
:词尾锚定,用于单词模式的右侧
\<pattern\>
:匹配完成单词
分组引用
xy*
表示y可以有也可以没有,但是我们把xy这两个字母当成一个整体呢?怎么办?这时候就要用到分组引用,其实就是用小括号将要引用的字符串括起来,当成一个整体看待。
NOTE:分组括号中的模式匹配的内容会被正则表达式引擎自动记录于内部的变量中,这些变量为:
1:模式从左侧起,第一个左括号以及与之匹配的右括号之间的模式所匹配到的字符。
2:模式从左侧起,第二个左括号以及与之匹配的右括号之间的模式所匹配到的字符。
括号可嵌套,不要交叉,括号有意义,所以要转义。
后向引用:引用前面的分组括号中的模式所匹配到的字符
练习
//显示/etc/passwd文件中不以/bin/bash结尾的行
[root@N2 ~]# grep -v "/bin/bash$" /etc/passwd
//找出/etc/passwd文件中的两位数或三位数
[root@N2 ~]# grep "\b[[:digit:]]\{2,3\}\b" /etc/passwd
[root@N2 ~]# grep "\<[0-9]\{2,3\}\>" /etc/passwd
//找出/etc/rc.d/rc.sysinit或/etc/grub2.cfg文件中,以至少一个空白字符开头、后后面非空白字符的行。
[root@N2 ~]# grep "^[[:space:]]\+.*[^[:space:]]" /etc/grub2.cfg
//找出netstat –tan命令的结果中以LISITEN后跟0、1或多个空白字符结尾的行。
[root@N2 ~]# netstat -tan | grep "LISTEN[[:space:]]*$"
4、扩展的正则表达式
扩展的正则表达式大致上基本的正则表达式是一样的,就是有一些细节上的区别:
次数的匹配的斜线没有了
分组引用当中支持”或者“
//找出/proc/meminfo文件中,所有以大写或小写s开头的行,至少有三种实现方式:
[root@N2 ~]# grep -i "^s" /proc/meminfo
[root@N2 ~]# grep "^[sS]" /proc/meminfo
[root@N2 ~]# egrep "^(s|S)" /proc/meminfo
//显示当前系统上root、centos或user1用户的相关信息
[root@N2 ~]# egrep "^(root|centos|user1)\b" /etc/passwd
//找出/etc/rc.d/init.d/funcitons文件中某单词后跟一个小括号的行
[root@N2 ~]# egrep -o "[_[:alnum:]]+\b\(\)" /etc/rc.d/init.d/functions
//使用echo命令输出一个绝对路径,使用egerp取于基名
echo /etc/passwd | egrep -o "[^/]+/?$"
echo /etc/passwd/ | egrep -o "[[:alnum:]]+/?$"
//取目录名
[root@kk ~]# echo /etc/passwd/ | egrep -o '^/[^/]+'
/etc
echo etc/passwd | egrep -o "^/?[^/]+/{1}"
echo etc/passwd/ | egrep -o "^/?[[:alnum:]]+\b/?"
//找出ifconfig当中的1-255之间的数
ifconfig | grep -E -o "\<([1-9]|[1-9][0-9]|1[0-9]{2}|2[0-5]{2})\>"
//找出ip地址(使用grep找IP不好用):
[root@N2 ~]# ifconfig eth0 | grep -E -o "([0-9]{1,3}\.){3}[0-9]{1,3}"
192.168.80.59
255.255.255.0
192.168.80.255
//添加bash用户,找到/etc/passwd文件当中用户名与shell名的行
[root@N2 ~]# egrep "^([^:]+\b).*\1$" /etc/passwd
egrep '(^.*):.*\1$' /etc/passwd