3个简单有用的工具,可在Linux中grep多个字符串

时间:2020-01-09 10:38:47  来源:igfitidea点击:

如何在单行中grep多个字符串?
是否可以使用单个命令从文件grep多个字符串?
如何在单个文件中匹配两个或者多个模式?
在多种情况下,我们需要grep文件中的多个字符串。

我们将使用以下工具来涵盖所有这些问题:

  • grep

  • awk

  • sed

grep多个字符串-语法

默认情况下,带有-e参数的grep用来grep一个特定的PATTERN
现在,该模式可以是字符串,正则表达式或者其他任何东西。
我们可以使用grep多次添加-e,因此我们已经可以使用grep捕获多个字符串。

-egrep一起使用

grep [args] -e PATTERN-1 -e PATTERN-2 .. FILE/PATH

pipeescape字符一起使用

egrep [args] "PATTERN1\|PATTER2\|PATTERN3" FILE/PATH

使用扩展grep(-E)使用不带有'escape'字符的pipe

grep [args] -E "PATTERN1|PATTER2|PATTERN3" FILE/PATH

或者

egrep [args] "PATTERN1|PATTER2|PATTERN3" FILE/PATH

说明:

这里的egrep是扩展的grep。
不赞成使用egrep或者fgrep这样的直接调用,但是直接调用是为了允许依赖它们的历史应用程序未经修改地运行。

正如我们可能在语法中观察到的那样,我们可以将grep与更多内置的args结合使用,以增强grepping功能。
现在,我们将在更多场景的不同示例中使用这些语法

对多个模式执行不区分大小写的grep

要执行不区分大小写的搜索,我们必须使用-i或者

--ignore-case , from the man page of grep:

java -i,--ignore-case忽略大小写区别,以便仅大小写不同的字符彼此匹配。
在本节中,我们将根据我们可以使用的语法对所有包含/var/log/messages中的错误,警告和致命的行进行grep表示:

# grep -i "error\|warn\|fatal" /var/log/messages

或者

# grep -i -e error -e warn -e fatal /var/log/messages

或者

# egrep -i "error\|warn\|fatal" /var/log/messages

或者

# grep -iE "error|warn|fatal" /var/log/messages

现在,由于我们将语法与-i的grep多个字符串组合在一起,因此grep将在/var/log/messages文件中执行区分大小写的搜索

打印文件名和grep输出

现在,我们可能会尝试对一堆文件的某个路径中的多个字符串执行" grep"操作。
在这种情况下,我们可能会获得带有行的匹配模式输出,但是默认情况下,我们将不会" NOT"获得单个匹配的" PATTERN"文件名。

要同时使用grep打印文件名,请使用-H或者--with-filename参数。
在grep的手册页中,

-H, --with-filename
      Print the file name for each match.  This is the default when there is more than one file to search.

因此,再次将我们的grep语法与-H参数结合使用,还可以在各行中同时打印文件名和匹配的字符串:

# grep -Hi "error\|warn\|fatal" /var/log/*

或者

# grep -Hi -e error -e warn -e fatal /var/log/*

或者

# egrep -Hi "error\|warn\|fatal" /var/log/*

或者

# grep -HiE "error|warn|fatal" /var/log/*

其中如果我们观察到的话,我已经在所有现有的grep命令中添加了-H,以查找/var/log/*目录下包含error,warn或者fatal的所有文件。
使用grep分配这些参数时,没有特定的顺序可循。

例如:

# grep -HiE "error|warn|fatal" /var/log/*

也可以写成

# grep -iHE "error|warn|fatal" /var/log/*

或者

# grep -EHi "error|warn|fatal" /var/log/*

或者

# grep -H -i -E "error|warn|fatal" /var/log/*

我们将从所有命令中获得相同的输出。
因此,正如我们所看到的,我们可以以不同的顺序编写一组参数,与grep组合或者单独编写,因此只要我们使用正确的参数,"顺序"就无关紧要。

grep路径中所有文件中的多个字符串

说明:

如我们所见,我们得到一些输出,例如grep:/var/log/anaconda:是一个目录,因为默认情况下,grep只会在提供的目录下的文件中搜索,而不会在子目录中搜索,因此抛出此错误。
要在所有目录和子目录内执行递归搜索,请对grep使用-r或者-R

Grep用于文件或者路径中的多个精确模式匹配

默认情况下,当我们使用grep搜索模式或者字符串时,它将以所有形式打印包含匹配模式的行。

例如,如果我们使用grep表示warn,则grep还将匹配警告,忽略警告等。
因为所有这些词都包含我们的字符串,即warn。
但是如果要求是仅打印完全匹配的单词(即警告),那么我们必须将-w或者--word-regexpgrep一起使用。
在grep的手册页中:

-w, --word-regexp
      Select only those lines containing matches that form whole words.  The test is that the  matching  substring  must  either  be  at  the
      beginning  of  the  line,  or  preceded  by  a  non-word constituent character.  Similarly, it must be either at the end of the line or
      followed by a non-word constituent character.  Word-constituent characters are letters, digits, and the underscore.  This option has no
      effect if -x is also specified.

要在/var/log/messages中搜索多个单词完全匹配的字符串,我们将使用

# grep -w "error\|warn\|fatal" /var/log/messages

或者

# grep -w -e error -e warn -e fatal /var/log/messages

或者

# egrep -w "error\|warn\|fatal" /var/log/messages

或者

# grep -Ew "error|warn|fatal" /var/log/messages

grep具有AND条件的多个字符串

在前面的示例中,我们使用" OR"条件来匹配多个字符串。
现在,如果我们需要搜索带有" AND"条件的多个字符串,即所有提供的模式必须在同一行中匹配

例如,我有这个文件:

# cat /tmp/somefile
Successfully activated sshd service
Successfully reloaded service
Successfully stopped service
Successfully enabled service
Successfully activated httpd service

我希望grep表示成功和激活的线路。
最简单的方法是先对第一个匹配项使用" grep",然后对下一个字符串进行" grep"

# grep -i "success" /tmp/somefile | grep -i activated
Successfully activated sshd service
Successfully activated httpd service

因此,我们现在有同时包含这两个字符串的行,但是此方法的缺点是,如果我们有多个字符串,那么我们将最终多次使用grep,看起来并不整洁

另外,我们也可以使用这种格式的grep

# grep -ie "success.*activated" -e "activated.*success" /tmp/somefile
Successfully activated sshd service
Successfully activated httpd service

由于我们不知道这两个字符串的出现顺序,因此我们以两种可能的顺序对这两种模式进行grep。
这项工作可以完成,但是对于多个字符串搜索而言,可能又是混乱的。

用grep排除多个模式

我们可以将grep与-v或者--invert-match一起使用来反转选择,即从匹配中排除提供的模式。
我们可以为排除列表提供多个字符串。
在此示例中,我们希望除/tmp/somefile中具有sshd或者已激活的行以外的所有行。

# grep -v "sshd\|activated" /tmp/somefile
Successfully reloaded service
Successfully stopped service
Successfully enabled service

使用awk搜索多个字符串-语法

对于大多数简单的用例,我们可以只使用grep来匹配多个字符串或者模式,但是对于复杂的用例,我们可以考虑使用" awk"作为替代。
将单个" PATTERN"与" awk"进行匹配的基本语法为:

awk '/PATTERN/' FILE

要匹配多种模式:

awk '/PATTERN1|PATTERN2/PATTERN3/' FILE

使用OR条件匹配多个模式

要对字符串或者模式执行不区分大小写的搜索,我们可以使用以下语法:

awk 'BEGIN{IGNORECASE=1} /PATTERN1|PATTERN2/PATTERN3/' FILE

例如,要对/var/log/messages中所有出现错误或者警告的行进行grep调用,我们可以使用:

# awk '/Error|warning/' /var/log/messages

但是为了不区分大小写,在本示例中,我们将使用IGNORECASE

# awk 'BEGIN{IGNORECASE=1} /Error|warning/' /var/log/messages

使用AND条件搜索多个模式

在上面的示例中,我们正在搜索具有" OR"条件的模式,即,如果找到了多个提供的字符串中的任何一个,则打印相应的匹配行。
但是要在所有提供的" PATTERN"匹配时打印行,我们必须使用" AND"运算符。
语法为:

awk '/PATTERN1/&& /PATTERN2/&& /PATTERN3/' FILE

现在,我们将使用此语法来搜索包含成功并在/tmp/somefile中激活的行。

# awk '/Success/&& /activated/' /tmp/somefile
Successfully activated sshd service
Successfully activated httpd service

为了执行不区分大小写的搜索,我们将使用以下语法:

awk 'BEGIN{IGNORECASE=1} /PATTERN1/&& /PATTERN2/&& /PATTERN3/' FILE

现在,在示例中使用以下语法:

# awk 'BEGIN{IGNORECASE=1}; /success/&& /activated/' /tmp/somefile
Successfully activated sshd service
Successfully activated httpd service

用awk排除多个模式

我们还可以从搜索中排除某些预定义的模式。
通用语法为:

awk '!/PATTERN1/&& !/PATTERN2/&& !/PATTERN3/' FILE

在这种语法中,我们要从搜索中排除所有三个" PATTERNS"。
我们可以根据需要在语法中添加或者删除更多模式。

例如,要打印除包含已激活的行以外的所有行

# awk '!/activated/' /tmp/somefile
Successfully reloaded service
Successfully stopped service
Successfully enabled service

使用sed匹配并打印多个字符串-语法

理想情况下,我们使用sed来主要搜索模式,然后对搜索模式或者行执行操作,例如删除,替换等。
但是在某些特定情况下,我们也可以使用sed来匹配单个或者多个模式从文件中打印匹配的内容。

匹配并打印单个模式的语法为:

sed -n '/PATTERN/p' FILE

这里我们使用-n(或者我们可以使用--quiet或者--silent)与p一起打印模式空间,即除非找到模式匹配项,否则不打印

类似地,匹配具有" OR"条件的多个字符串的语法为:

sed -n '/PATTERN1\|PATTERN2\|PATTERN3/p' FILE

另外,我们也可以使用sed和-e来添加多个脚本(即条件)以匹配我们的情况下的模式。

# sed -e '/PATTERN1/b' -e '/PATTERN2/b' -e d FILE

在sed的手册页中,

-e script	: add the script to the commands to be executed
b label 	: Branch to label; if label is omitted, branch to end of script.
d        	: Delete pattern space.  Start next cycle.

我们可以根据需要使用提供的语法n多次添加或者删除PATTERN

例如,要匹配已激活并重新加载到我们文件中

# sed -e '/activated/b' -e '/reload/b' -e d /tmp/somefile
Successfully activated sshd service
Successfully reloaded service
Successfully activated httpd service

不区分大小写的多个字符串匹配

没有类似于sed中的awk或者grep的单个参数来对单个或者多个模式执行不区分大小写的匹配。
因此,我们必须提供可能存在的char的大写和小写字符,我们认为可能存在变化。

例如,在我的情况下,文件可能包含成功或者带有大写字母S的成功,因此我将其放在示例中:

# sed -e '/[Ss]uccess/b' -e '/reload/b' -e d /tmp/somefile
Successfully activated sshd service
Successfully reloaded service
Successfully stopped service
Successfully enabled service
successfully activated httpd service   <-- One with lowercase

因此,现在" sed"将查找大写和小写S的成功匹配。
因此,如果我们觉得更多字符可能会有变化,那么对于所有可能的选项,我们都必须使用相同的方法

排除多个字符串

我们还可以使用上述语法中的NOT()运算符排除多个字符串。

sed -n '/PATTERN1\|PATTERN2/!p' FILE

例如打印除具有sshd的行外的所有行并重新加载

# sed -n '/sshd\|reload/!p' /tmp/somefile
Successfully stopped service
Successfully enabled service
successfully activated httpd service