grep 简介
grep(global search regular expression(RE) and print out the line,全面搜索正则表达式并把行打印出来)是一种强大的文本搜索工具,它能使用正则表达式搜索文本,并把匹配的行打印出来。Unix/Linux 系统中的 grep 家族通常包括 grep、egrep 和 fgrep。
egrep 是 grep 的扩展版本,支持更多的正则表达式元字符。fgrep(fixed grep 或 fast grep)则将所有的字母都视为普通字符,即正则表达式中的元字符会失去特殊含义,仅代表其字面意义。在大多数 Linux 发行版中,使用的是 GNU 版本的 grep,它功能更强大,可以通过 -G(默认,基本正则)、-E(扩展正则,等同于 egrep)和 -F(固定字符串,等同于 fgrep)命令行选项来切换模式。
grep 的工作方式是在一个或多个文件中搜索给定的字符串模式(模板)。如果模式包含空格,则必须用引号引起来。模式之后的所有参数被视为文件名。搜索结果会输出到屏幕,而不会修改原文件。
grep 在 Shell 脚本中非常有用,因为它会返回一个状态值来指示搜索结果:
- 0:表示搜索成功,找到了匹配项。
- 1:表示搜索未成功,未找到匹配项。
- 2:表示搜索的文件不存在或无法读取。
脚本可以利用这些返回值来进行条件判断和自动化文本处理。
grep 正则表达式元字符集(基本集)
以下是 grep 在默认模式(-G)下支持的基本正则表达式元字符:
^:锚定行的开始。例如:'^grep'匹配所有以 grep 开头的行。$:锚定行的结束。例如:'grep$'匹配所有以 grep 结尾的行。.:匹配任意一个非换行符的字符。例如:'gr.p'匹配 gr 后接任意一个字符,然后是 p。*:匹配前一个字符零次或多次。例如:' *grep'匹配零个或多个空格后紧跟 grep 的行。.*组合表示匹配任意长度的任意字符(除换行符外)。[]:匹配一个指定范围内的字符。例如:'[Gg]rep'匹配 Grep 和 grep。[^]:匹配一个不在指定范围内的字符。例如:'[^A-FH-Z]rep'匹配不以 A-F 和 H-Z 中字母开头,但紧跟 rep 的行。(..):标记匹配的字符(分组),后续可用1,2等引用。例如:'(love)',love 被标记为 1。<:锚定单词的开始。例如:'<grep'匹配包含以 grep 开头的单词的行。>:锚定单词的结束。例如:'grep>'匹配包含以 grep 结尾的单词的行。x{m}:重复字符 x 恰好 m 次。例如:'o{5}'匹配包含连续 5 个 o 的行。x{m,}:重复字符 x 至少 m 次。例如:'o{5,}'匹配至少有连续 5 个 o 的行。x{m,n}:重复字符 x,至少 m 次,不多于 n 次。例如:'o{5,10}'匹配 5 到 10 个连续的 o。w:匹配文字和数字字符,等同于[A-Za-z0-9_]。例如:'Gw*p'匹配以 G 开头,后跟零个或多个文字数字字符,然后是 p。W:w的反置形式,匹配一个非单词字符(如标点、空格)。b:单词边界。例如:'bgrepb'只匹配独立的单词 grep。
用于 egrep 和 grep -E 的元字符扩展集
使用 egrep 或 grep -E 时,支持以下扩展元字符,语法更简洁:
+:匹配前一个字符一次或多次。例如:'[a-z]+able'匹配一个或多个小写字母后跟 able 的字符串。?:匹配前一个字符零次或一次。例如:'gr?p'匹配 grp 或 grep。|:或操作,匹配多个模式之一。例如:'grep|sed'匹配 grep 或 sed。():分组,无需转义。例如:'love(able|rs)ov+'匹配 loveable 或 lovers,后跟一个或多个 ov。x{m}, x{m,}, x{m,n}:功能同基本集中的x{m}等,但写法更简洁。
POSIX 字符类
为了保持不同语言环境字符编码的一致性,POSIX 标准定义了一些字符类。在 grep 中(除 fgrep 模式外),可以将它们放在 [[: :]] 内使用。例如,[[:alnum:]] 等同于 [A-Za-z0-9]。
[:alnum:]:字母数字字符。[:alpha:]:字母字符。[:digit:]:数字字符。[:graph:]:非空字符(非空格、控制字符)。[:lower:]:小写字母。[:cntrl:]:控制字符。[:print:]:可打印字符(包括空格)。[:punct:]:标点符号。[:space:]:所有空白字符(空格、制表符、换行等)。[:upper:]:大写字母。[:xdigit:]:十六进制数字(0-9, a-f, A-F)。
Grep 常用命令选项
-A NUM, -B NUM, -C NUM:显示匹配行及其后(After)、前(Before)、前后(Context)各 NUM 行。原“-?”表述不准确,已修正。-b, --byte-offset:在匹配行前打印该行在文件中的字节偏移量。-c, --count:只打印匹配的行数,不显示具体内容。-f FILE, --file=FILE:从指定文件中读取要搜索的模式。-h, --no-filename:搜索多文件时,不显示文件名前缀。-i, --ignore-case:忽略大小写。-q, --quiet, --silent:静默模式,不输出任何信息,只通过退出状态返回结果。-l, --files-with-matches:只打印包含匹配项的文件名。-L, --files-without-match:只打印不包含匹配项的文件名。-n, --line-number:显示匹配行的行号。-s, --no-messages:不显示文件不存在或不可读的错误信息。-v, --invert-match:反向匹配,只显示不匹配的行。-w, --word-regexp:强制模式匹配整个单词。-E, --extended-regexp:使用扩展正则表达式(等同于 egrep)。-F, --fixed-strings:将模式视为固定字符串,而非正则表达式(等同于 fgrep)。-V, --version:显示 grep 版本信息。
实例
掌握 grep 的关键在于熟练运用正则表达式。以下是一些常见的使用实例:
$ ls -l | grep '^a'
通过管道过滤 ls -l 的输出,只显示以字母 a 开头的行。
$ grep 'test' d*
显示所有以 d 开头的文件中包含字符串 test 的行。
$ grep 'test' aa bb cc
显示在 aa, bb, cc 三个文件中匹配 test 的行。
$ grep '[a-z]{5}' aa
显示文件 aa 中所有包含至少 5 个连续小写字母的字符串的行。
$ grep 'w(es)t.*1' aa
如果 west 被匹配,则其中的 es 会被存储并标记为第一组(1),然后搜索任意字符(.*)后面紧跟着另一个 es 的行。如果使用 egrep 或 grep -E,则无需对括号进行转义,可以直接写成 'w(es)t.*1'。