我想在几个文件中找到与两种模式之一匹配的所有行。我尝试通过键入

grep (foo|bar) *.txt
找到所需的模式,但是shell将|解释为管道,并在bar不是可执行文件时抱怨。 br />
如何在同一组文件中grep表示多个模式?

评论

Grep的可能重复项:如何添加“ OR”条件?

grep'word1 \ | word2 \ | word3'/ path / to / file

#1 楼

首先,您需要保护模式以免被shell扩展。最简单的方法是用单引号引起来。单引号可防止它们之间的任何内容扩展(包括反斜杠);然后,您唯一不能做的就是在模式中使用单引号。

grep -- 'foo*' *.txt


(还请注意--选项结束标记以停止某些grep包括GNU grep的实现,例如通过处理名为-foo-.txt的文件(将从shell扩展到*.txt)作为选项(即使它在此处跟随非选项参数)也是如此。

如果确实需要单引号,则可以将其写为'\''(结束字符串文字,文字引号,打开字符串文字)。模式至少有两种语法。旧的默认语法(基本正则表达式)不支持替代(|)运算符,尽管某些版本将其作为扩展名,但使用反斜杠编写。

grep -- 'foo*'\''bar' *.txt


可移植的方法是使用更新的语法,扩展的正则表达式。您需要将-E选项传递给grep才能将其选中(以前是通过egrep单独的命令²完成的)。

grep -- 'foo\|bar' *.txt


当您正在寻找任何其他选项时,这是另一种可能多个模式中的一个(与使用析取法构建复杂模式相对)是将多个模式传递给grep。您可以通过在每个模式前面加上-e选项来实现此目的。

grep -E -- 'foo|bar' *.txt


或将模式放在多行上:

grep -e foo -e bar -- *.txt


或将这些模式存储在文件中,每行一个并运行

grep -- 'foo
bar' *.txt


请注意,如果*.txt扩展为单个文件,则grep不会像文件多于一个文件时那样为其名称的匹配行加上前缀。要解决此问题,对于某些grep实现(例如GNU grep),可以使用-H选项,对于任何实现,都可以将/dev/null作为附加参数传递。


¹一些grep实现对于ksh通配符,甚至更支持与-P的perl兼容的或与-X-K的增强的ksh通配符...。在尚未安装POSIX或GNU实用程序的Solaris等其他系统上,则egrep是您的唯一选择,因为其egrep不支持/bin/grep-e-f-E或多行模式

评论


附带说明-固定模式后,您应该真正养成fgrep或grep -F的习惯,对于小的模式,差异可以忽略不计,但是随着它们变得更长,好处开始显现出来...

–TC1
2012年4月26日在9:37

根据手册页弃用了@ TC1 fgrep

–ramn
2014年7月22日在8:41

@ TC1 grep -F是否具有实际的性能优势取决于grep的实现:它们中的某些始终使用相同的算法,因此-F仅对解析模式所花费的时间有所不同,而对搜索时间没有影响。例如,GNU grep使用-F不会更快(它还有一个使grep -F在多字节语言环境中变慢的错误-与grep相同的常量模式实际上会更快!)。另一方面,对于大型文件,-F确实使BusyBox grep受益匪浅。

–吉尔斯'所以-不再是邪恶的'
2014年7月22日在8:53



也许应该提到的是,对于仅用于正则表达式一部分的更复杂的模式,可以将其与“ \(”和“ \””分组(转义用于默认的“基本正则表达式” )(?)。

– Peter Mortensen
2015年5月20日9:45



请注意,egrep早于grep -E。它不是特定于GNU的(与Linux毫无关系)。实际上,您仍然会发现像Solaris这样的系统,其中默认grep仍然不支持-E。

–StéphaneChazelas
16年6月7日在11:27

#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,因为我从示例中学到了东西。现在我学到了一些新东西。 :)

评论


万一我可以按以下方式使用它:egrep“ [f] oo | [b] ar” * .txt由于此答案stackoverflow.com/a/9375940/2402577 @user unknown

–警报
3月5日18:13

@alper:对我来说这没有意义。在您的链接问题中,阻止命令本身不出现在ps列表中是一种黑客手段,但是您在txt文件中使用了grep。使用这些括号,您可以选择其他替代品,但请不要提出。 egrep“ [nm] oon | [jt] ar” * .txt将查找月亮,中午,罐子或焦油。对于链接的示例,如果命令的名称为command,我将使用其他人建议的pgrep或ps -C命令。仅在这种特定情况下,在不同位置摸索“终端”,此技巧才非常聪明。对于选项,请使用:echo“ erminal” | egrep“ [tT]?erminal”

–用户未知
3月6日0:26

#3 楼

就像TC1所说的,-F似乎是可用的选项:

$> cat text
some text
foo
another text
bar
end of file

$> patterns="foo
bar" 

$> grep -F "${patterns}" text
foo
bar


评论


@poige我不知道$'foo \ nbar'选项,不确定扩展在这里如何工作,需要查找,但是谢谢,这真的很有用。

–haridsv
2012年11月5日,12:26

真好!这个选项似乎也使它运行得更快(因为它禁用了正则表达式)。

– qwertzguy
18年1月30日,0:44

#4 楼

首先,您需要对特殊字符使用引号。其次,即使这样,grep也不会直接理解交替。您将需要使用egrep,或者(仅与GNU grep一起使用)grep -E。 br />

评论


实际上,grep -E比egrep更标准。

– jw013
2012年4月26日在1:14



#5 楼

如果不需要正则表达式,则将fgrepgrep -F与多个-e参数一起使用会更快,例如:

fgrep -efoo -ebar *.txt


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

评论


另请参阅此页面上的注释,其中提到已弃用fgrep。

–phk
16-12-27在20:21

#6 楼

您可以尝试使用以下命令获取结果:

egrep 'rose.*lotus|lotus.*rose' some_file


#7 楼

管道(|)是特殊的外壳字符,因此需要转义(\|)或按手册引用(man bash):


引用用于消除特殊含义。外壳上的某些字符或单词。它可用于禁用对特殊字符的特殊处理,以防止保留字被识别为此类,并防止参数扩展。引号

转义字符是无引号的反斜杠(\)。


请参阅:Bash中需要转义哪些字符? br />这里有几个示例(使用尚未提及的工具):



使用ripgrep: > rg "foo|bar" *.txt



使用rg -e foo -e bar *.txt



git grep

注意:它也支持诸如git grep --no-index -e foo --or -e bar--and--or之类的布尔表达式。





关于每行的AND运算,请参见:如何使用多个AND模式运行grep? />
有关每个文件的AND操作,请参阅:如何检查文件中是否存在所有多个字符串或正则表达式?

#8 楼

一种用于多种模式的grep廉价而愉悦的方式:

$ echo "foo" > ewq ; echo "bar" >> ewq ; grep -H -f ewq *.txt ; rm ewq


评论


可以从解释中受益。

– Peter Mortensen
17年12月1日在4:12

原因是grep的-f选项采用具有多个模式的文件。而不是创建一个临时文件(您以后可能会忘记删除它),而只需使用Shell的进程替换即可:grep -f <(echo foo; echo bar)* .txt

–雅各布
18-3-29在8:03



#9 楼

我有访问日志,其中的日期格式很愚蠢:[30 / Jun / 2013:08:00:45 +0200]

,但我需要将其显示为:30 / Jun / 2013 08:00 :45

问题是,在我的grep语句中使用“ OR”,我在两条单独的行上收到了两个匹配表达式。

这里是解决方法:

grep -in myURL_of_interest  *access.log  | \
grep -Eo '(\b[[:digit:]]{2}/[[:upper:]][[:lower:]]{2}/[[:digit:]]{4}|[[:digit:]]{2}:[[:digit:]]{2}:[[:digit:]]{2}\b)'   \
| paste - - -d" " > MyAccess.log


#10 楼

TL; DR:如果要在匹配多个模式之一之后执行更多操作,请将其括起来,如\(pattern1\|pattern2\)

示例:我想查找包含名称为“ date”的变量的所有位置'定义为String或int。 (例如,“ int cronDate =“或” String textFormattedDateStamp =“):

cat myfile | grep '\(int\|String\) [a-zA-Z_]*date[a-zA-Z_]* =' 


使用grep -E,您无需对括号或管道进行转义,即,grep -E '(int|String) [a-zA-Z_]*date[a-zA-Z_]* ='

#11 楼

这对我有用

 root@gateway:/home/sshuser# aws ec2 describe-instances --instance-ids i-2db0459d |grep 'STATE\|TAG'

**STATE**   80      stopped

**STATE**REASON     Client.UserInitiatedShutdown    Client.UserInitiatedShutdown: User initiated shutdown

**TAGS**    Name    Magento-Testing root@gateway:/home/sshuser#
 


#12 楼

有多种方法可以做到这一点。


grep 'foo\|bar' *.txt
egrep 'foo|bar' *.txt
find . -maxdepth 1 -type f -name "*.txt" | xargs grep 'foo\|bar'
find . -maxdepth 1 -type f -name "*.txt" | xargs egrep 'foo|bar'

第3个和第4个选项将仅在文件中grep并避免使用目录名称中带有.txt
因此,根据您的用例,您可以使用上面提到的任何选项。
谢谢!

#13 楼

要添加到@geekosaur的答案中,如果您有多个也包含制表符和空格的模式,请使用以下命令

grep -E "foo[[:blank:]]|bar[[:blank:]]"


其中[[:blank:]]是代表一个字符的RE字符类空格或制表符