如何使用 grep
大多数人认为系统管理员和程序员只是摆弄旋钮和二极管。他们的目标是?进入互联网的虚拟现实,将代码的二进制力量聚集到我们今天使用的应用程序和基础设施中。大多数人会失望地得知,系统管理员和代码猴子更经常地戳文本流,希望得到正确的响应。
如果您是系统管理员或程序员,并且发现自己痴迷于POSIX系统上的文本流,那么您可能遇到过grep
,或者遇到过希望可以使用此命令的时候。
安装grep
该grep
命令是全局正则表达式 print的首字母缩写,最初是 UNIX 联合创始人 Ken Thompson 电脑上的一个个人实用脚本。(该工具之所以得到广泛发布,是因为 Thompson 的部门主管 Doug McIlroy 要求开发一个“在文件中查找内容”的工具。)
从那时起,该grep
命令的代码已被几位不同的程序员编写和重写,但它的名字一直保留了下来。这种情况很方便,因为这意味着无论您使用哪种 UNIX 或类 UNIX 系统,您都可以grep
使用命令。不过,这个事实也可能令人困惑:虽然大多数grep
命令都试图相互互换,但并非所有grep
命令都完全相同。
本文专门介绍了Linux 系统上的默认系统GNUgrep
grep
,但如果您使用的是 UNIX 家族的其他成员,这里还提供了一些信息。
- BSD(以及主要使用 BSD 工具的系统):附带 BSD 版本
grep
,但 GNUgrep
在 ports 树中可用。 - Illumos:一些发行版附带了 Sun 版本
grep
,该版本可能与 GNU 和 BSD 版本不同。GNUgrep
可从 Illumos 发行版的存储库获取。 - Solaris:随附 Sun 版本
grep
,可能与 GNU 和 BSD 版本不同。GNUgrep
可从OpenCSW获得。
最后,您可以通过安装开源Cygwingrep
包在 Windows 上获得更多命令,该包提供了大量的 GNU 和开源工具集合。
在文本中搜索字符串
的规范用法grep
是在较大的文本主体中搜索精确的字符串,并返回包含成功匹配的行。以下是示例:
$ grep BSD example.txt
NetBSD
OpenBSD
在文本流中搜索字符串
另一种常用的方法grep
是使用管道,使其成为一种过滤器。这种技术有一些优点。其一是grep
通过仅搜索另一个进程的结果来帮助缩小 的范围。例如,此命令iana
仅在 源代码的最后 10 行中搜索example.com
,而不是搜索整个页面:
$ curl example.com | tail | grep iana
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 1270 100 1270 0 0 3177 0 --:--:-- --:--:-- --:--:-- 3175
<p><a href="http://www.iana.org/domains/example">More information...</a></p>
这种策略还可以grep
用于其他可能无效的情况。例如,您通常无法grep
通过二进制文件,因为二进制文件不包含太多原始文本。但是,您可以使用诸如这样的命令strings
来提取二进制文件的纯文本,然后grep
对结果使用如下命令:
$ strings example.xcf | grep gimp
gimp xcf v011
gimp-image-grid
gimp-image-metadata
gimprsttuvvutrqpljjiijlnv{
klmnmlkjgimpsvxwqjeehlnopg
为结果添加背景信息
一行文本被视为以换行符结尾的字符串,具体来说, 0x0D0A
或\r\n
,分别是回车符 (CR) 和换行符 (LF) ASCII字符。如果您的文本文件中有超长的行,那么您的结果可能包含比您预期更多的数据,因为 grep
不会将字符串脱离上下文。它返回整行。
--only-matching
(或-o
简称)选项grep
仅打印行的匹配部分。如需添加上下文,请使用选项--line-number
(-n
简称)查看文件中匹配模式出现的行号。例如:
$ grep --only-matching --line-number Fedora example.txt
2:Fedora
要了解某个模式在文件中出现的方式或原因,一种常见的方法是查看匹配项上方的行、紧接其后的行,或两者。有三种方法可以做到这一点,而且它们就像 ABC(字面意思)一样容易记住:
--after-context
(或-A
)在匹配后显示指定数量的行--before-context
(或-B
)显示匹配项前的指定行数--context
(或-C
)显示匹配项前后指定数量的行
例如,要查看匹配模式前的两行:
$ grep Baz -B2 metasyntactic.list
Foo
Bar
Baz
要在比赛后看到三行:
$ grep Baz -A3 metasyntactic.list
Baz
Qux
Quux
Quuz
比赛前后都可以看到两条线:
$ grep -C2 metasyntactic.list
Foo
Bar
Baz
Qux
Quux
一次搜索多个文件
该grep
命令非常灵活,您不必grep
一次只搜索一个文件,甚至不必创建一个花哨的for 循环 来循环搜索您想要搜索的每个文件。您可以列出多个文件作为目标,或使用通配符来定位多个文件。默认情况下,grep
打印任何匹配的文件的名称,以及包含匹配模式的完整行,如下所示:
$ grep Fedora distro.list example.txt fake.txt
distro.list:Fedora creates an innovative, free, and open source platform for hardware, clouds, and containers that enables software developers and community members to build tailored solutions for their users.
example.txt:Fedora Linux
您可以仅获取包含与选项匹配的文件的名称--files-with-matches
(-l
简称):
$ grep Fedora --files-with-matches distro.list example.txt fake.txt
distro.list
example.txt
您可以使用(或)获取不包含匹配项的文件的名称:--files-without-match
-L
$ grep Fedora --files-without-matches distro.list example.txt fake.txt
fake.txt
要搜索特定文件夹的所有子目录中的所有文件,请使用--recursive
或-r
:
$ grep Norm --recursive --only-matching docbooks-xsl-1.79.1
docbook-xsl-1.79.1/tests/refentry.007.xml:Norm
docbook-xsl-1.79.1/tests/refentry.007.xml:Norm
docbook-xsl-1.79.1/tests/refentry.007.xml:Norm
docbook-xsl-1.79.1/tests/refentry.007.ns.xml:Norm
...
忽略大小写
有时您不知道或不关心字符串是小写还是大写。使用 --ignore-case
(或-i
如果您很懒,或者如果您的版本grep
允许)不区分大小写。例如:
$ grep --ignore-case fedora example.txt
Fedora Linux
反向搜索
grep
在搜索文件时,可以反转它,以便只返回不匹配的行,而不是返回所有成功匹配的行。此功能的 POSIX 选项是-v
,因此它应该适用于大多数grep
版本。GNU 使用的助记符友好选项是--invert-match
。以下是一个例子:
$ grep --invert-match fedora example.txt
Debian Linux
Mageia Linux
Slackware Linux
NetBSD
OpenBSD
...
正则表达式
正则表达式 (或“regex”) 是一个太大的话题,无法在此介绍,幸运的是,另一篇文章对此进行了很好的介绍。正如那篇文章所述,正则表达式自早期以来就一直是 UNIX 高级用户必备的工具之一。因此,它们被广泛使用也就不足为奇了grep
。毕竟,“正则表达式”就在其名称中。
唯一需要使用的正则表达式grep
是您要搜索的字符串的绝对值(文字值),到目前为止所有示例都使用这个值。但是,熟悉正则表达式会让它变得grep
更加强大。
并非所有正则表达式都相同。该术语描述了发明模式以匹配某些事物的过程。任何人都可以为正则表达式发明一种模式,因此grep
的正则表达式只是众多规则集中的一个。
开始学习正则表达式的最佳地点是其 GNU 信息页面,位于正则表达式grep
部分。你可以使用以下命令找到此页面:
$ info grep "Regular Expressions"
基本特征如下:
- 点 (
.
) 匹配任意单个字符。例如,s.urce
匹配source
和sauce
。 - A
?
表示正则表达式中的前一项是可选的,并且最多匹配一次。因此qu?x
匹配qux
或quix
但永远不会匹配quux
,因为u
在正则表达式中只出现一次。 - 通配符
*
也基于其前面的内容,规定某项必须匹配零次或多次。此行为与 Bash shell 的 不同*
,后者无条件匹配零个或多个字符,因此如果您习惯使用 Bash,请不要感到困惑。 - 该
+
字符还会修改其前面的字符,规定某项必须匹配一次或多次。
grep
使用选项激活正则表达式--extended-regexp
,或者只是-E
为了简单起见。这是一个非常常见的用例,大多数 Linux 发行版都提供了快捷egrep
命令,以节省您键入的时间-E
(尽管 GNUgrep
信息页面指出这egrep
已被正式弃用)。一些正则表达式语法可以在grep
不使用-E
选项的情况下工作,但不要让这一事实欺骗您自满。虽然有些字符无论如何都可以工作,但其他字符在grep
处理之前会被您的 shell 解释,因此您的正则表达式不会给您准确的结果。
这是一个示例文件,名为metasyntactic.list
:
foobar
foo
bar
baz
qux
quux
quuz
corge
grault
garply
waldo
fred
plugh
xyzzy
thud
wibble
wobble
wubble
flob
这里有一些基于正则表达式的 grep 搜索。
$ grep -E b.+ metasyntactic.list
foobar
bar
baz
wibble
wobble
wubble
$ grep -E ^b.. metasyntactic.list
bar
baz
与使用纯正则表达式相比,POSIX 正则表达式表示法可能更简单,它与 兼容grep
。POSIX 正则表达式允许使用人类可识别的关键字(例如[:alpha:]
或 )[:digit:]
来识别要匹配的内容。使用这种格式编写有效的模式与以往一样困难,但至少您正在处理的各个部分更容易解读。
为了防止您的 POSIX 正则表达式符号被 Bash 解释,请使用双括号,如下所示:
$ grep -E ^b[[:alpha:]]+
bar
baz
$ grep -E b[[:alpha:]]+$ metasyntactic.list
foobar
bar
baz
wibble
wobble
wubble
的正则表达式还有很多内容grep
。通过研究您想要匹配的内容示例,然后交叉引用grep
信息页面,您可以学习如何有效地使用此命令。
为成功而进行 Grepping
该grep
命令复杂而强大。它非常适合在各种文件和数据流中快速查找文本片段。您使用的越多grep
,您就越熟悉它;您越熟悉它,您就会学到越多的选项。开始使用grep
进行命令和 shell 脚本吧 s.+ner[[:space:]]than[[:space:]]l.t[[:alpha:]]r
!
本网站表达的观点均为作者本人观点,而非作者所在雇主或 Red Hat 的观点。本网站发布的内容为社区贡献,仅供参考,并非且不旨在作为 RED HAT 文档、支持或建议。