Linux中的Grep命令(查找文件中的文本)

评论 0 浏览 0 2018-10-24

grep命令代表 "全局正则表达式打印",它是Linux中最强大和最常用的命令之一。

grep 搜索一个或多个输入文件中与给定模式相匹配的行,并将每个匹配的行写到标准输出。如果没有指定文件,grep从标准输入中读取,这通常是另一个命令的输出。

在这篇文章中,我们将通过实际的例子和对最常见的GNU grep选项的详细解释,向你展示如何使用grep命令。

grep 命令的句法

grep命令的句法如下。

grep [OPTIONS] PATTERN [FILE...]

方括号内的项目是可选择的。

  • OPTIONS - 零个或多个选项。Grep包括个选项,控制其行为。
  • PATTERN--搜索模式。
  • FILE - 零个或更多的输入文件名。

为了能够搜索该文件,运行该命令的用户必须有对该文件的读取权限。

在文件中搜索一个字符串

grep命令最基本的用法是在一个文件中搜索一个字符串(文本)。

例如,要显示/etc/passwd文件中包含字符串bash的所有行,你将运行以下命令。

grep bash /etc/passwd

输出结果应该是这样的。

输出

root:x:0:0:root:/root:/bin/bash
linuxize:x:1000:1000:linuxize:/home/linuxize:/bin/bash

如果字符串包括空格,你需要用单引号或双引号将其括起来。

grep "Gnome Display Manager" /etc/passwd

反向匹配(排除)

要显示与模式不匹配的行,请使用-v(或--invert-match)选项。

例如,如果要打印不包含字符串nologin的行,你可以使用。

grep -v nologin /etc/passwd

输出

root:x:0:0:root:/root:/bin/bash
colord:x:124:124::/var/lib/colord:/bin/false
git:x:994:994:git daemon user:/:/usr/bin/git-shell
linuxize:x:1000:1000:linuxize:/home/linuxize:/bin/bash

使用Grep来过滤命令的输出结果

一个命令的输出可以通过管道用grep进行过滤,只有与给定模式相匹配的行才会被打印在终端上。

例如,要想知道哪些进程是以用户www-data的身份在你的系统上运行的,你可以使用下面的ps命令。

ps -ef | grep www-data

输出

www-data 18247 12675  4 16:00 ?        00:00:00 php-fpm: pool www
root     18272 17714  0 16:00 pts/0    00:00:00 grep --color=auto --exclude-dir=.bzr --exclude-dir=CVS --exclude-dir=.git --exclude-dir=.hg --exclude-dir=.svn www-data
www-data 31147 12770  0 Oct22 ?        00:05:51 nginx: worker process
www-data 31148 12770  0 Oct22 ?        00:00:00 nginx: cache manager process

你也可以在一个命令中连接多个管道。正如你所看到的,在上面的输出中,还有一行包含grep进程。如果你不希望这一行被显示出来,可以把输出传给另一个grep实例,如下图所示。

ps -ef | grep www-data | grep -v grep

输出

www-data 18247 12675  4 16:00 ?        00:00:00 php-fpm: pool www
www-data 31147 12770  0 Oct22 ?        00:05:51 nginx: worker process
www-data 31148 12770  0 Oct22 ?        00:00:00 nginx: cache manager process

要递归搜索一个模式,请用-r选项(或--recursive)来调用grep。当使用这个选项时,grep将搜索指定目录下的所有文件,跳过递归遇到的符号链接。

要跟踪所有的符号链接,而不是-r,请使用-R选项(或--dereference-recursive)。

下面是一个例子,显示了如何在/etc目录内的所有文件中搜索字符串linuxize.com

grep -r linuxize.com /etc

输出将包括以文件的完整路径为前缀的匹配行。

输出

/etc/hosts:127.0.0.1 node2.linuxize.com
/etc/nginx/sites-available/linuxize.com:    server_name linuxize.com   www.linuxize.com;

如果你使用-R选项,grep将跟随所有的符号链接。

grep -R linuxize.com /etc

注意下面输出的最后一行。当grep-r一起调用时,这一行不会被打印出来,因为Nginx的sites-enabled目录下的文件是指向sites-available目录下的配置文件的符号链接。

输出

/etc/hosts:127.0.0.1 node2.linuxize.com
/etc/nginx/sites-available/linuxize.com:    server_name linuxize.com   www.linuxize.com;
/etc/nginx/sites-enabled/linuxize.com:    server_name linuxize.com   www.linuxize.com;

只显示文件名

要抑制默认的grep输出,只打印包含匹配模式的文件名,请使用-l(或--files-with-matches)选项。

下面的命令在当前工作目录中搜索所有以.conf结尾的文件,并且只打印包含字符串linuxize.com的文件名。

grep -l linuxize.com *.conf

输出结果将看起来像这样。

输出

tmux.conf
haproxy.conf

-l选项通常与递归选项-R结合使用。

grep -Rl linuxize.com /tmp

默认情况下,grep是区分大小写的。这意味着大写字母和小写字母被视为不同的字符。

要想在搜索时忽略大小写,请在调用grep时加上-i选项(或--ignore-case)。

例如,在没有任何选项的情况下搜索Zebra时,以下命令不会显示任何输出,即有匹配的行。

grep Zebra /usr/share/words

但是,如果你使用-i选项进行不区分大小写的搜索,它将同时匹配大写和小写字母。

grep -i Zebra /usr/share/words

指定 "Zebra "将匹配 "zebra"、"ZEbrA "或该字符串的任何其他大写和小写字母的组合。

输出

zebra
zebra's
zebras

搜索完整的字词

当搜索一个字符串时,grep将显示该字符串嵌入到更大的字符串中的所有行。

例如,如果你搜索 "gnu",所有将 "gnu "嵌入更大的词中的行,如 "cygnus "或 "magnum",都将被匹配。

grep gnu /usr/share/words

输出

cygnus
gnu
interregnum
lgnu9d
lignum
magnum
magnuson
sphagnum
wingnut

要想只返回那些指定的字符串是整个单词的行(用非单词字符括起来),请使用-w(或--word-regexp)选项。

字符包括字母数字字符(a-zA-Z,和0-9)和下划线(_)。所有其他字符被视为非文字字符。

如果你运行与上面相同的命令,包括-w选项,grep命令将只返回那些将gnu作为一个单独的词包括在内的行。

grep -w gnu /usr/share/words

输出

gnu

显示行号

-n(或--line-number)选项告诉grep显示包含匹配模式的字符串的行号。当使用这个选项时,grep将匹配的内容打印到标准输出,并以行号为前缀。

例如,要显示/etc/services文件中包含以匹配的行号为前缀的字符串bash的行,你可以使用下面的命令。

grep -n 10000 /etc/services

下面的输出显示,我们在第10423和10424行找到了匹配的内容。

输出

10423:ndmp            10000/tcp
10424:ndmp            10000/udp

计数匹配

要想在标准输出中打印匹配行的数量,请使用-c(或--count)选项。

在下面的例子中,我们正在计算以/usr/bin/zsh为shell的账户的数量。

$ regular expression
$ grep -c '/usr/bin/zsh' /etc/passwd

输出

4

静谧模式

-q(或--quiet)告诉grep以安静模式运行,不在标准输出上显示任何东西。如果找到一个匹配的文件,该命令将以状态0退出。当在shell脚本中使用grep时,这很有用,因为你想检查一个文件是否包含一个字符串,并根据结果执行某种动作。

下面是一个在安静模式下使用grep作为if语句中的测试命令的例子。

if grep -q PATTERN filename
then
    echo pattern found
else
    echo pattern not found
fi

基本的正则表达式

GNU Grep有三个正则表达式功能集,即基本功能集、扩展功能集和Perl兼容功能集。

默认情况下,grep将模式解释为一个基本的正则表达式,其中除了元字符以外的所有字符实际上都是与自己匹配的正则表达式。

下面是一个最常用的元字符的列表。

  • 使用^(圆点)符号来匹配行首的表达。在下面的例子中,只有当字符串kangaroo出现在一行的最开始时才会匹配。

    grep "^kangaroo" file.txt
  • 使用$(美元)符号来匹配行末的表达。在下面的例子中,只有当字符串kangaroo出现在一行的最末尾时才会匹配。

    grep "kangaroo$" file.txt
  • 使用.(句号)符号来匹配任何单个字符。例如,为了匹配任何以kan开头然后有两个字符并以字符串roo结尾的东西,你可以使用以下模式。

    grep "kan..roo" file.txt
  • 使用[ ](括号)来匹配括号内的任何单个字符。例如,找到包含acceptaccent的行,你可以使用以下模式。

    grep "acce[np]t" file.txt
  • 使用[^ ]来匹配任何不在括号内的单一字符。下面的模式将匹配任何含有co(any_letter_except_l)a的字符串组合,如cocacobalt等,但不会匹配含有cola的行。

    grep "co[^l]a" file.txt

要转义下一个字符的特殊含义,请使用\(反斜杠)符号。

扩展的正则表达式

要将该模式解释为一个扩展的正则表达式,请使用-E(或--extended-regexp)选项。扩展正则表达式包括所有的基本元字符,以及额外的元字符,以创建更复杂和强大的搜索模式。下面是一些例子。

  • 匹配并提取给定文件中的所有电子邮箱地址。

    grep -E -o "\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,6}\b" file.txt
  • 匹配并从给定文件中提取所有有效的IP地址。

    grep -E -o '(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)' file.txt

-o选项用于只打印匹配的字符串。

搜索多个字符串(模式)

两个或更多的搜索模式可以使用OR运算符|连接起来。

默认情况下,grep将模式解释为一个基本的正则表达式,其中元字符(如|)失去了特殊的意义,必须使用它们的反斜线版本。

在下面的例子中,我们正在搜索Nginx日志错误文件中所有出现的fatalerrorcritical的字样。

grep 'fatal\|error\|critical' /var/log/nginx/error.log

如果你使用扩展的正则表达式选项-E,那么运算符|就不应该被转义,如下图所示。

grep -E 'fatal|error|critical' /var/log/nginx/error.log

要想在匹配行之前打印特定的行数,请使用-B(或--before-context)选项。

例如,要在匹配行之前显示五行前导上下文,您可以使用以下命令:

grep -B 5 root /etc/passwd

要想在匹配行后打印特定的行数,请使用-A(或--after-context)选项。

例如,要在匹配行之后显示五行尾随上下文,您可以使用以下命令:

grep -A 5 root /etc/passwd

总结

grep命令允许你在文件中搜索一个模式。如果找到了匹配,grep会打印出包含指定模式的行。

Grep用户手册页面上,还有很多关于Grep的知识可以学习。

如果你有任何问题或反馈意见,请随时留言。

最后更新2023-09-16
0 个评论
标签