我想在多个文件中查找与两种模式之一匹配的所有行。我试图通过输入来找到我正在寻找的模式
grep (foo|bar) *.txt
但 shell 将 解释|
为管道,并在bar
不是可执行文件时发出抱怨。
如何 grep 查找同一组文件中的多个模式?
答案1
首先,您需要保护模式不被 shell 扩展。最简单的方法是用单引号引起来。单引号可防止它们之间的任何内容扩展(包括反斜杠);那么你唯一不能做的就是在模式中使用单引号。
grep -- 'foo*' *.txt
(还请注意--
选项结束标记,以阻止grep
包括 GNU 在内的某些实现grep
将例如调用的文件-foo-.txt
(将由 shell 从 扩展*.txt
)视为选项(即使它在此处遵循非选项参数))。
如果确实需要单引号,可以将其写为'\''
(结束字符串文字、文字引号、开放字符串文字)。
grep -- 'foo*'\''bar' *.txt
其次,grep 至少支持两种模式语法。旧的默认语法(基本正则表达式) 不支持交替 ( |
) 运算符,尽管某些版本将其作为扩展,但用反斜杠编写。
grep -- 'foo\|bar' *.txt
可移植的方法是使用更新的语法,扩展正则表达式。您需要传递-E
选项来grep
选择它(以前是使用egrep
单独的命令²完成的)
grep -E -- 'foo|bar' *.txt
当您只是寻找多个模式中的任何一个(而不是使用析取构建复杂模式)时,另一种可能性是将多个模式传递给grep
.您可以通过在每个模式前面加上选项来完成此操作-e
。
grep -e foo -e bar -- *.txt
或者将图案放在几行上:
grep -- 'foo
bar' *.txt
或者将这些模式存储在一个文件中,每行一个并运行
grep -f that-file -- *.txt
请注意,如果*.txt
扩展到单个文件,grep
则不会像存在多个文件时那样在匹配行前添加其名称前缀。要解决这个问题,对于某些grep
实现(例如 GNU )grep
,您可以使用该-H
选项,或者对于任何实现,您可以/dev/null
作为额外参数传递。
一些grep
实现甚至支持更像 perl 兼容的实现,带有-P
, 或增强的带有-X
,-K
的 ksh 通配符...
² 虽然egrep
POSIX 已弃用,并且有时在某些系统上不再找到它,但在某些其他系统(如 Solaris)上,当尚未安装 POSIX 或 GNU 实用程序时,thenegrep
是您唯一的选择,因为它/bin/grep
不支持-e
、-f
、-E
或\|
多个线条图案
答案2
egrep "foo|bar" *.txt
或者
grep "foo\|bar" *.txt
grep -E "foo|bar" *.txt
有选择地引用 gnu-grep 的手册页:
-E, --extended-regexp
Interpret PATTERN as an extended regular expression (ERE, see below). (-E is specified by POSIX.)
Matching Control
-e PATTERN, --regexp=PATTERN
Use PATTERN as the pattern. This can be used to specify multiple search patterns, or to protect a pattern
beginning with a hyphen (-). (-e is specified by POSIX.)
(...)
grep understands two different versions of regular expression syntax: “basic” and “extended.” In GNU grep, there
is no difference in available functionality using either syntax. In other implementations, basic regular
expressions are less powerful. The following description applies to extended regular expressions; differences for
basic regular expressions are summarized afterwards.
一开始我没有进一步阅读,所以我没有意识到其中的细微差别:
Basic vs Extended Regular Expressions
In basic regular expressions the meta-characters ?, +, {, |, (, and ) lose their special meaning; instead use the
backslashed versions \?, \+, \{, \|, \(, and \).
我总是使用egrep和不必要的parens,因为我从例子中学习。现在我学到了一些新东西。 :)
答案3
就像 TC1 所说,-F
似乎是可用的选项:
$> cat text
some text
foo
another text
bar
end of file
$> patterns="foo
bar"
$> grep -F "${patterns}" text
foo
bar
答案4
如果不需要正则表达式,使用fgrep
orgrep -F
和多个 -e 参数会更快,如下所示:
fgrep -efoo -ebar *.txt
fgrep
(或者grep -F
)比常规 grep 快得多,因为它搜索固定字符串而不是正则表达式。