3个简单有用的工具,可在Linux中grep多个字符串
如何在单行中grep多个字符串?
是否可以使用单个命令从文件grep多个字符串?
如何在单个文件中匹配两个或者多个模式?
在多种情况下,我们需要grep文件中的多个字符串。
我们将使用以下工具来涵盖所有这些问题:
grep
awk
sed
grep多个字符串-语法
默认情况下,带有-e
参数的grep
用来grep一个特定的PATTERN
。
现在,该模式可以是字符串,正则表达式或者其他任何东西。
我们可以使用grep多次添加-e,因此我们已经可以使用grep捕获多个字符串。
将-e
与grep
一起使用
grep [args] -e PATTERN-1 -e PATTERN-2 .. FILE/PATH
将pipe
与escape
字符一起使用
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-regexp
与grep
一起使用。
在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