grep 模式匹配命令
基本操作
grep
命令用于打印输出文本中匹配的模式串,它使用正则表达式作为模式匹配的条件。grep 支持三种正则表达式引擎,分别用三个参数指定:
参数 | 说明 |
---|---|
-E | POSIX 扩展正则表达式,ERE |
-G | POSIX 基本正则表达式,BRE |
-P | Perl 正则表达式,PCRE |
不过在你没学过 perl 语言的大多数情况下你将只会使用到 ERE 和 BRE,所以我们接下来的内容都不会讨论到 PCRE 中特有的一些正则表达式语法(它们之间大部分内容是存在交集的,所以你不用担心会遗漏多少重要内容)。
在通过grep命令使用正则表达式之前,先介绍一下它的常用参数:
参数 | 说明 |
---|---|
-b | 将二进制文件作为文本来进行匹配 |
-c | 统计以模式匹配的数目 |
-i | 忽略大小写 |
-n | 显示匹配文本所在行的行号 |
-v | 反选,输出不匹配行的内容 |
-r | 递归匹配查找 |
-A n | n 为正整数,表示 after 的意思,除了列出匹配行之外,还列出后面的 n 行 |
-B n | n 为正整数,表示 before 的意思,除了列出匹配行之外,还列出前面的 n 行 |
–color=auto | 将输出中的匹配项设置为自动颜色显示 |
注:在大多数发行版中是默认设置了 grep 的颜色的,你可以通过参数指定或修改GREP_COLOR环境变量。
使用正则表达式
使用基本正则表达式,BRE
- 位置
查找 /etc/group 文件中以 shiyanlou 为开头的行
grep 'shiyanlou' /etc/group
grep '^shiyanlou' /etc/group
- 数量
# 将匹配以'z'开头以'o'结尾的所有字符串
echo 'zero\nzo\nzoo' | grep 'z.*o'
# 将匹配以'z'开头以'o'结尾,中间包含一个任意字符的字符串
echo 'zero\nzo\nzoo' | grep 'z.o'
# 将匹配以'z'开头,以任意多个'o'结尾的字符串
echo 'zero\nzo\nzoo' | grep 'zo*'
注意:其中 \n 为换行符
- 选择
# grep默认是区分大小写的,这里将匹配所有的小写字母
echo '1234\nabcd' | grep '[a-z]'
# 将匹配所有的数字
echo '1234\nabcd' | grep '[0-9]'
# 将匹配所有的数字
echo '1234\nabcd' | grep '[[:digit:]]'
# 将匹配所有的小写字母
echo '1234\nabcd' | grep '[[:lower:]]'
# 将匹配所有的大写字母
echo '1234\nabcd' | grep '[[:upper:]]'
# 将匹配所有的字母和数字,包括0-9,a-z,A-Z
echo '1234\nabcd' | grep '[[:alnum:]]'
# 将匹配所有的字母
echo '1234\nabcd' | grep '[[:alpha:]]'
下面包含完整的特殊符号及说明:
特殊符号 | 说明 |
---|---|
[:alnum:] | 代表英文大小写字母及数字,亦即 0-9,A-Z,a-z |
[:alpha:] | 代表任何英文大小写字母,亦即 A-Z,a-z |
[:blank:] | 代表空白键与 [Tab] 按键两者 |
[:cntrl:] | 代表键盘上面的控制按键,亦即包括 CR,LF,Tab,Del… |
[:digit:] | 代表数字而已,亦即 0-9 |
[:graph:] | 除了空白字节(空白键与 [Tab] 按键)外的其他所有按键 |
[:lower:] | 代表小写字母,亦即 a-z |
[:print:] | 代表任何可以被列印出来的字符 |
[:punct:] | 代表标点符号(punctuation symbol),即:",’,?,!,;,:,#,$… |
[:upper:] | 代表大写字母,亦即 A-Z |
[:space:] | 任何会产生空白的字符,包括空格键,[Tab],CR 等等 |
[:xdigit:] | 代表 16 进位的数字类型,因此包括: 0-9,A-F,a-f 的数字与字节 |
- 注意
之所以要使用特殊符号,是因为上面的 [a-z] 不是在所有情况下都管用,这还与主机当前的语系有关,即设置在 LANG 环境变量的值,zh_CN.UTF-8 的话 [a-z],即为所有小写字母,其它语系可能是大小写交替的如,“a A b B…z Z”,[a-z] 中就可能包含大写字母。所以在使用 [a-z] 时请确保当前语系的影响,使用 [:lower:] 则不会有这个问题。
# 排除字符
echo 'geek\ngood' | grep '[^o]'
^
放到中括号内为排除字符,否则表示行首。
使用扩展正则表达式,ERE
要通过 grep
使用扩展正则表达式
需要加上 -E
参数,或使用 egrep
。
- 数量
# 只匹配"zo"
echo 'zero\nzo\nzoo' | grep -E 'zo{1}'
# 匹配以"zo"开头的所有单词
echo 'zero\nzo\nzoo' | grep -E 'zo{1,}'
推荐掌握 {n,m}
即可 +,?,* 这几个不太直观,且容易弄混淆。
- 选择
# 匹配"www.shiyanlou.com"和"www.google.com"
echo 'www.shiyanlou.com\nwww.baidu.com\nwww.google.com' | grep -E 'www\.(shiyanlou|google)\.com'
# 或者匹配不包含"baidu"的内容
echo 'www.shiyanlou.com\nwww.baidu.com\nwww.google.com' | grep -Ev 'www\.baidu\.com'
因为 .
号有特殊含义,所以需要转义。
校招真题
小明在做数据分析的时候需要提取文件中关于数字的部分,同时还要提取用户的邮箱部分,但是有的行不是数组也不是邮箱,现在需要你在 data2 这个文件中帮助他用正则表达式匹配出数字部分和邮箱部分。
数据文件可以使用以下命令下载:
$ cd /home/shiyanlou
$ wget https://labfile.oss.aliyuncs.com/courses/1/data2
下载后的数据文件路径为 /home/shiyanlou/data2。
目标
在文件 /home/shiyanlou/data2 中匹配数字开头的行,将所有以数字开头的行都写入 /home/shiyanlou/num 文件。
在文件 /home/shiyanlou/data2 中匹配出正确格式的邮箱,将所有的邮箱写入 /home/shiyanlou/mail 文件,注意该文件中每行为一个邮箱。
答案
grep '^[0-9]' /home/shiyanlou/data2 > /home/shiyanlou/num
grep -E '[[: alnum:]]+@[[: alnum:]]+ \.com' maill /home/shiyanlou/data2 > /home/shiyanlou/num