文本处理三剑客之 grep
grep简介
grep(Global search REgular expression and Print out the line)是Linux上的文本处理三剑客之一,另外两个是sed和awk.
grep是文本搜索工具,根据用户指定的pattern(由文本字符及正则表达式元字符编写的过滤条件)对目标文本逐行进行匹配检查并打印出符合条件的行.
grep有三个版本:grep,egrep和fgrep. egrep是扩展的grep,等同于grep -E,fgrep是快速grep,不支持正则表达式.
之前觉得glob跟grep正则很相似,其实他们的区别还挺大:
glob匹配文件名,grep匹配文件内容
glob是全部匹配,grep是部分匹配
正则表达式(Regular Expression,在代码中常简写为regex、regexp或RE):
正则表达式是对字符串(包括普通字符(例如,a 到 z 之间的字母)和特殊字符(称为“元字符”))操作的一种逻辑公式,就是用事先定义好的一些特定字符、及这些特定字符的组合,组成一个“规则字符串”,这个“规则字符串”用来表达对字符串的一种过滤逻辑。正则表达式是一种文本模式,模式描述在搜索文本时要匹配的一个或多个字符串。
不同版本的grep对正则表达式的支持有所不同:
grep:默认是使用基本正则表达式(BRE)
egrep:支持扩展的正则表达式(ERE)
fgrep:不支持正则表达式(但搜索速度快)
grep命令:
命令格式:
grep [OPTIONS] PATTERN [FILE...]
grep [OPTIONS] [-e PATTERN | -f FILE] [FILE...]
常用选项:
--color=auto:对匹配到的文本着色高亮显示
-i:忽略字符大小写
-o:仅显示匹配到的文本自身(默认显示匹配到的文本整行)
-v,--invert-match:显示不能被pattern匹配到的行
-E,--extened-regexp:支持扩展的正则表达式(ERE).相当于egrep命令
-F,--fixed-strings:相当于fgrep命令
-q,--quiet,--silent:静默模式,不输出任何信息,取命令退出状态码时常用
-G,--basic-regexp:支持使用基本正则表达式
-P,--perl-regexp:支持使用pcre正则表达式(支持元字符很多)
-e PATTERN,--regexp=PATTERN:使用多模式
-f FILE,--file=:FILE为每行包含了一个pattern的文本文件,即grep script,把模式写在一个文件里,通过读取文件(脚本文件),来匹配
-c:显示统计匹配到的行数
-r,--recursive:对目录下所有文件里的内容根据模式匹配
-A #,--after-context=#:表示显示匹配到行的后面#行
-B #,--before-context=#:表示显示匹配到行的前面#行
-C #,-#,--context=#:表示显示匹配到行的前后#行
示例:
# grep 'root' /etc/passwd:如果模式里有变量要用双引号
# grep -v 'root' /etc/passwd:反向匹配,显示所有没有被匹配的行
# grep -i 'bash' bash.txt:忽略字符大小写
# grep -o 'root' /etc/passwd:仅显示匹配到的文本自身
# grep -q 'root' /etc/passwd:静默模式
示例:
# grep -e "r..t" -e "bash" /etc/passwd:使用多模式
# grep -f /root/test/mypat /etc/passwd:使用保存在文件里的匹配模式,模式无需加引号.
# grep -A 1 "^[op]" /etc/passwd:显示匹配到的行后面的一行
# grep -B 2 "^[op]" /etc/passwd:显示匹配到的行前面的两行
# grep -C 1 "^[op]" /etc/passwd:显示匹配到的行前后各一行
基本正则表达式元字符:
1、字符匹配:
.:匹配任意单个字符
[]:匹配范围内的任意单个字符
[^]:匹配范围外的单个字符
[:digit:]:任意单个数字
[:lower:]:任意单个小写字母
[:upper:]:任意单个大写字符
[:alpha:]:任意单个字母
[:alnum:]:任意单个字母和数字
[:space:]:任意单个空白字符
[:blank:]:任意单个空格和tab
[:punct:]:任意单个标点符号
[:cntrl:]:任意单个控制符
[:graph:]:任意单个能显示的符号
[:print:]:任意单个可打印符号
[:xdigit:]:任意单个十六进制字符
示例:
# ifconfig | grep "r..":r后跟两个字符的行
# ifconfig | grep -i "i[a-z][a-z]":不区分大小写,i后跟两个字母的行
# ifconfig | grep "i[[:alpha:]][[:space:]]":i后跟一个字母再跟一个空格的行
2、次数匹配:
用在要指定其出现的次数的字符后面,用于限制其前面的字符要出现的次数,默认工作在贪婪模式
*:匹配前面的字符出现的任意次(0,1或多次)
grep "x*y":只要有y就匹配
.*:匹配任意长度的任意字符,相当于glob中的*
grep "x.*y":在x和y之间可出现任意长度任意字符即匹配
\+:匹配前面的字符至少1次(1次或多次);\为转义符
grep "x\+y":y之前必须出现一个x
\?:匹配前面的字符0次或1次,即前面的字符可有可无
grep "x\?y":只要有y就匹配
\{m\}:匹配其前面的字符出现m次,m为非负整数
grep "x\{2\}y":y前出现2次x就匹配
\{m,n\}:匹配其前面的字符出现m次,m为非负整数;闭区间[m,n]
\{0,n\}:至多n次
因为会匹配多次,所以全部都会匹配
\{m,\}:至少m次
示例:
# ifconfig | grep "i[[:alpha:]]\{3\}":匹配i后跟3个字母的行
# ifconfig | grep "i[[:alpha:]]\{3,\}":匹配i后跟至少3个字母的行
3、位置锚定:
限制使用模式搜索文本,限制模式所匹配到的文本只能出现于目标文本的哪个位置
^:行首锚定;用于模式的最左侧,^PATTERN
$:行尾锚定;用于模式的最右侧,PATTERN$
^PATTERN$:要让PATTERN完全匹配一整行
^$:匹配空行;
^[[:space:]].*$:匹配空白行;
示例:
# grep "^r..t" /etc/passwd:匹配r开头后跟两个字符再跟t的行
# grep "l.\{3\}n" /etc/passwd:匹配l后跟3个字符再跟n的行
# grep "l.\{3\}n$" /etc/passwd:匹配l后跟3个字符再跟n结尾的行
# grep "[[:space:]]\+" /etc/passwd:匹配至少连续出现一个空格的行
单词:非特殊字符组成的连续字符(字符串)都称为单词
\<或\b:词首锚定,用于单词模式的左侧,格式为\<PATTERN,/bPATTERN
\>或\b:词尾锚定,用于的承诺模式的右侧,格式为PATTERN\>,PATTERN\b
示例:
# grep "\<r..t" /etc/passwd:匹配单词词首:r后跟两个字符再跟t的行
# grep "\<r..t\>" /etc/passwd:匹配单词:r后跟两个字符再跟t的行
# ifconfig | grep "\<[0-9]\{3\}\>":匹配单词:三个数字
更多实例:
1、显示/etc/passwd文件中不以bash结尾的行
# grep -v 'bash$' /etc/passwd
2、找出/etc/passwd文件中的三位或四位数
# grep '\<[0-9]\{3,4\}\>' /etc/passwd
3、找出/etc/grub2.cfg文件中,以至少一个空白字符开头,后面又跟了一非空白字符的行
# grep '^[[:space:]]\+[^[:space:]]' /etc/grub2.cfg
4、找出"netstat -tan"命令的结果中,以‘LISTEN’后跟0或多个空白字符结尾的行
# netstat -tan | grep 'LISTEN[[:space:]]*$'
5、找出“fdisk -l”命令结果中,以/dev/后跟sd或hd及一个小写字母的行
# fdisk -l | grep '/dev/[sh]d[a-z]\>'
6、找出“ldd /usr/bin/cat”命令的结果中的文件路径
# ldd /usr/bin/cat | grep -o '/[^[:space:]]\+'
4、分组与引用:
\(PATTERN\):将此PATTERN匹配到的字符当作一个不可分割的整体进行处理
注意:分组括号中的模式匹配到的字符会被正则表达式引擎自动记录于内部变量中,这些变量是\1,\2,\3,...
例如:pat1\(pat2\)pat3\(pat4\(pat5)pat6\)
\n:模式中的第n个左括号以及与之匹配的右括号之间的模式所匹配到的字符串(不是模式,而是模式匹配的结果)
\1:表示第一组括号总的PATTERN匹配到的的字符串;上例:pat2
\2:表示第二组括号总的PATTERN匹配到的的字符串;上例:pat4\(pat5)pat6
\3:表示第三组括号总的PATTERN匹配到的的字符串;上例:pat5
...
示例,文档test内容如下:
he love his lover
he like his lover
he love his liker
he like his liker
.*l..e.*l..er
\(l..e\).*\1r
# grep -o 'l..e.*l..er' test:不能完成精确匹配
# grep -o '\(l..e\).*\1r' test:分组可完成精确匹配
后向引用:引用前面的括号中的模式所匹配到的字符串
egrep命令:
命令格式
egrep [OPTIONS] PATTERN [FILE...]
命令选项:
egrep的选项与grep相同
扩展正则表达式的元字符:无需转义符
字符匹配:
.:匹配任意单个字符
[]:匹配范围内的任意单个字符
[^]:匹配范围外的单个字符
[:digit:]:任意单个数字
[:lower:]:任意单个小写字母
[:upper:]:任意单个大写字符
[:alpha:]:任意单个字母
[:alnum:]:任意单个字母和数字
[:space:]:任意单个空格
[:blank:]:任意单个空格和tab
[:punct:]:任意单个标点符号
次数匹配:
*:匹配前面的字符(可有可无)出现的任意次(0,1或多次)
?:匹配前面的字符0次或1次,即前面的字符可有可无
+:匹配前面的字符至少1次(1次或多次)
{m}:匹配其前面的字符出现m次,m为非负整数
{m,n}:匹配其前面的字符出现m次,m为非负整数
{0,n}:至多n次
{m,}:至少m次
位置锚定:
^:行首锚定;用于模式的最左侧,^PATTERN
$:行尾锚定;用于模式的最右侧,PATTERN$
^PATTERN$:要让PATTERN完全匹配一整行
^$:匹配空行
\<,\b:词首锚定,用于单词模式的左侧,格式为\<PATTERN,/bPATTERN
\>,\b:词尾锚定,用于的承诺模式的右侧,格式为PATTERN\>,PATTERN\b
分组及引用:
(pattern):分组,括号中的模式匹配到的字符会被存储于正则表达式引擎内部的变量中
后向引用:\1,\2,\3,...
或者:
a|b:a或者b
C|cat:表示C或cat
(C|c)at:表示Cat或cat
egrep实例:
1、显示/etc/passwd文件中不以bash结尾的行
# egrep -v 'bash$' /etc/passwd
2、找出/etc/passwd文件中的三位或四位数
# egrep '\<[0-9]{3,4}\>' /etc/passwd
3、找出/etc/grub2.cfg文件中,以至少一个空白字符开头,后面又跟了一非空白字符的行
# egrep '^[[:space:]]+[^[:space:]]' /etc/grub2.cfg
4、找出"netstat -tan"命令的结果中,以‘LISTEN’后跟0或多个空白字符结尾的行
# netstat -tan | egrep 'LISTEN[[:space:]]*$'
5、找出“fdisk -l”命令结果中,以/dev/后跟sd或hd及一个小写字母的行
# fdisk -l | egrep '/dev/[sh]d[a-z]\>'
# fdisk -l | egrep '/dev/(s|h)d[a-z]\>'
6、找出“ldd /usr/bin/cat”命令的结果中的文件路径
# ldd /usr/bin/cat | egrep -o '/[^[:space:]]+'
7、找出/proc/meninfo文件中,所有以大写或小写s开头的行,至少用三种方式实现
# egrep "^(s|S)" /proc/meminfo
# grep "^[sS]" /proc/meminfo
# grep -i "^s" /proc/meminfo
8、显示当前系统上root,centos,或slackware用户的相关信息
# egrep "^(root|centos|slackware)\>" /etc/passwd
# egrep "^(root|centos|slackware):" /etc/passwd
9、echo输出一个绝对路径,使用grep取出基名
# echo /etc/passwd/ | egrep -o "[^/]+/?$"
10、找出ifconfig命令结果中的1-255之间的整数
# ifconfig| egrep "\<([1-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\>"
11、添加用户bash、testbash、及nologin,要求前三个用户的默认shell为/bin/bash,而后找出其用户名与shell相同的用户
# egrep "^([a-z0-9]+)\>.*\1$" /etc/passwd