如何 grep 查找具有管道字符的模式的多个模式?

如何 grep 查找具有管道字符的模式的多个模式?

我想在多个文件中查找与两种模式之一匹配的所有行。我试图通过输入来找到我正在寻找的模式

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 通配符...

² 虽然egrepPOSIX 已弃用,并且有时在某些系统上不再找到它,但在某些其他系统(如 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

如果不需要正则表达式,使用fgreporgrep -F和多个 -e 参数会更快,如下所示:

fgrep -efoo -ebar *.txt

fgrep(或者grep -F)比常规 grep 快得多,因为它搜索固定字符串而不是正则表达式。

相关内容