Answers:
首先,您需要保护模式以免被外壳扩展。最简单的方法是用单引号引起来。单引号可以防止它们之间的任何内容扩展(包括反斜杠);您唯一不能做的就是在模式中使用单引号。
grep 'foo*' *.txt
如果确实需要单引号,则可以将其写为'\''
(结束字符串文字,文字引号,开放字符串文字)。
grep 'foo*'\''bar' *.txt
其次,grep支持两种模式语法。旧的默认语法(基本正则表达式)不支持alteration(|
)运算符,尽管某些版本将其作为扩展名,但使用反斜杠编写。
grep 'foo\|bar' *.txt
可移植的方法是使用更新的语法,扩展的正则表达式。您需要传递-E
选项将grep
其选中。在Linux上,您也可以键入egrep
代替grep -E
(在其他unice上,您可以将其设为别名)。
grep -E 'foo|bar' *.txt
当您只是寻找几种模式中的任何一种时(相对于使用析取来构建复杂模式的另一种可能)是将多个模式传递给grep
。您可以通过在每个模式之前添加该-e
选项来实现。
grep -e foo -e bar *.txt
fgrep
或的习惯grep -F
,对于小的模式,差异可以忽略不计,但是随着时间的延长,好处开始显现出来……
grep -F
具有实际的性能优势取决于grep的实现:它们中的某些无论如何都应用相同的算法,因此,这-F
仅对解析模式所花费的时间有所不同,而与搜索时间无关。例如,GNU grep的运行速度并不快-F
(它还有一个使grep -F
多字节语言环境变慢的错误-相同的常量模式grep
实际上快得多!)。另一方面,BusyBox grep确实从-F
大文件中受益匪浅。
egrep
早grep -E
。它不是特定于GNU的(与Linux毫无关系)。实际上,您仍然会发现像Solaris这样的系统,其中的默认值grep
仍然不支持-E
。
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,因为我从示例中学到了东西。现在我学到了一些新东西。:)
就像TC1所说的,-F
似乎是可用的选择:
$> cat text
some text
foo
another text
bar
end of file
$> patterns="foo
bar"
$> grep -F "${patterns}" text
foo
bar
如果您不需要正则表达式,则使用它fgrep
或grep -F
使用多个-e参数会更快,如下所示:
fgrep -efoo -ebar *.txt
fgrep
(或者grep -F
)比常规grep快得多,因为它搜索固定字符串而不是正则表达式。
fgrep
已过时的提及评论。
竖线(|
)是特殊的外壳字符,因此需要转义(\|
)或按手册引用(man bash
):
引用用于将某些字符或单词的特殊含义删除。它可用于禁用对特殊字符的特殊处理,以防止保留字被这样识别,并防止参数扩展。
用双引号引起来的字符将保留引号中所有字符的字面值
不带引号的反斜杠(
\
)是转义字符。
请参阅:在Bash中需要转义哪些字符?
以下是一些示例(使用尚未提及的工具):
使用ripgrep
:
rg "foo|bar" *.txt
rg -e foo -e bar *.txt
使用git grep
:
git grep --no-index -e foo --or -e bar
注意:它也支持布尔表达式,如--and
,--or
和--not
。
有关每行的AND操作,请参见:如何使用多个AND模式运行grep?
有关每个文件的AND操作,请参阅:如何检查文件中是否存在所有多个字符串或正则表达式?
我有访问日志,其中的日期格式很愚蠢:[30 / Jun / 2013:08:00:45 +0200]
但我需要将其显示为:30 / Jun / 2013 08:00:45
问题是在我的grep语句中使用“ OR”时,我在两条单独的行上收到了两个match表达式。
解决方法如下:
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
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_]* ='
这对我有用
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#
有多种方法可以做到这一点。
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
名称中包含目录。
因此,根据您的用例,您可以使用上述任何选项。
谢谢!!
要添加到@geekosaur的答案中,如果您有多个也包含制表符和空格的模式,请使用以下命令
grep -E "foo[[:blank:]]|bar[[:blank:]]"
[[:blank:]]
RE字符类在哪里,代表空格或制表符