Linux中的Grep命令(查找文件中的文本)
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-z
,A-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
使用
[ ]
(括号)来匹配括号内的任何单个字符。例如,找到包含accept
或accent
的行,你可以使用以下模式。grep "acce[np]t" file.txt
使用
[^ ]
来匹配任何不在括号内的单一字符。下面的模式将匹配任何含有co(any_letter_except_l)a
的字符串组合,如coca
、cobalt
等,但不会匹配含有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日志错误文件中所有出现的fatal
、error
和critical
的字样。
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的知识可以学习。
如果你有任何问题或反馈意见,请随时留言。