Shell编程中关于grep命令的详细解读

2024-10-08 16:32:35 浏览数 (2)

Grep是 Global Regular Expression Print的缩写,Grep是Linux/Unix命令行工具,是一种强大的文本搜索工具。它不仅可以简单地匹配字符串,还可以通过使用一些高级技巧来实现更复杂的搜索操作。

grep命令主要分为三种:grep,egrep和fgrep,其中egrep扩展支持正则表达式,而fgrep不支持正则表达式。

基本语法为:

代码语言:shell复制
grep [options] pattern [file...]
grep [options] [-e pattern] [-f file] [file]

grep命令在shell中返回值有三种情况:

  • 返回值0:表示找到了匹配的内容
  • 返回值1:表示没有找到匹配的内容
  • 返回值2:表示脚本出错或者搜索的文件不存在

通常使用$?来捕获grep命令的返回值,其实跟我在之前文章《Shell编程中关于函数退出状态码的讨论》 的一样,$? 可以捕获 grep命令的返回值,也可以捕获函数的退出状态码。

关于grep的作用域,有两种理解方式:

  • 可以使用grep [options] pattern [file...] ,这个意思是在指定文件中进行查找pattern
  • 可以使用 grep -r pattern dir ,这个意思是在指定文件夹中递归查找pattern。其中的options -r即表示递归的含义。
1 关于options 命令参数详释

grep的常用的命令参数如下:

-A[n]A 表示after,在..之后。显示n 1行,除显示匹配到的pattern所在的行,并显示该行之后的n行

代码语言:shell复制
[root@iZuf6gxtsgxni1r88kx9rtZ linux_cmd]# grep -n -A2 'Bird flu' science.txt 
107:Bird flu case raises fear of human spread
108-A case of bird flu in Missouri has researchers concerned 
109-because the infected person had no known contact with potential animal carriers of the disease. The

-B[n]B 表示before,在..之前。显示n 1行,除显示匹配到的pattern所在的行,并显示该行之前的n行

代码语言:shell复制
[root@iZuf6gxtsgxni1r88kx9rtZ linux_cmd]# grep -n -B2 'Bird flu' science.txt 
105-Flora Graham, senior editor, Nature Briefing
106-With contributions by Jacob Smith
107:Bird flu case raises fear of human spread

-C[n]C 表示context,上下文。显示2n 1行,除显示匹配到的pattern所在的行,并显示该行之前和之后的各n行

代码语言:shell复制
[root@iZuf6gxtsgxni1r88kx9rtZ linux_cmd]# grep -n -C2 'Bird flu' science.txt 
105-Flora Graham, senior editor, Nature Briefing
106-With contributions by Jacob Smith
107:Bird flu case raises fear of human spread
108-A case of bird flu in Missouri has researchers concerned 
109-because the infected person had no known contact with potential animal carriers of the disease. The 

-ii表示ignore-case ,忽略大小写

代码语言:shell复制
[root@iZuf6gxtsgxni1r88kx9rtZ linux_cmd]# grep -in h5n1 science.txt 
110:United States is experiencing an ongoing outbreak of H5N1 avian influenza in dairy cattle. Data from this new case could reveal whether it’s reached a 
112:no requirement for farmers to test cows for H5N1 and the country has failed to get a handle on exactly how the virus is spreading.

-oo表示output,表示仅输出匹配的字符串,而不是匹配到的字符串所在的行

代码语言:shell复制
[root@iZuf6gxtsgxni1r88kx9rtZ linux_cmd]# grep -oin h5n1 science.txt 
110:H5N1
112:H5N1

-vv表示verse,表示相反,即不输出匹配的字符串所在行,而输出未匹配的所有行。

由于我的文件中行数过多,在这里不做脚本案例展示。

-ll表示file with matches,意为仅输出文件内容匹配pattern的文件名称

代码语言:shell复制
[root@iZuf6gxtsgxni1r88kx9rtZ jiangms]# grep -l -ir nature linux_cmd/*
linux_cmd/science.txt

-LL表示file without match,意为仅输出文件内容中无法匹配pattern以外的文件名称,其实跟-v的逻辑是一致的。

同样由于文件过多,暂不展示案例脚本

-cc表示count,表示文件中匹配pattern的行数

代码语言:shell复制
[root@iZuf6gxtsgxni1r88kx9rtZ jiangms]# grep -c -i nature linux_cmd/science.txt 
25

-d:默认情况下,grep是在当前目录中查找,当当前目录中存在文件夹,那么会报grep: ... : Is a directory ,这样会影响阅读效果,解决方式有两种,一种是使用上述提到的-r的递归的命令避免,另一种是使用-d skip来避免,如下:

代码语言:shell复制
[root@iZuf6gxtsgxni1r88kx9rtZ jiangms]# grep -i -l nature linux_cmd/*
linux_cmd/science.txt
grep: linux_cmd/shtool-2.0.8: Is a directory
grep: linux_cmd/test: Is a directory
[root@iZuf6gxtsgxni1r88kx9rtZ jiangms]# grep -i -l -d skip nature linux_cmd/*
linux_cmd/science.txt

通过-d skip 来跳开子文件夹的方式,来避免 grep: ... : Is a directory 的提醒。

与之相对应还有一个相反的命令-d recurse等同于-r

-V表示version的意思,可以通过该命令获知系统中的grep的版本号情况

代码语言:shell复制
[root@iZuf6gxtsgxni1r88kx9rtZ jiangms]# grep -V
grep (GNU grep) 3.1
Copyright (C) 2017 Free Software Foundation, Inc.
License GPLv3 : GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>.
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.

Written by Mike Haertel and others, see <http://git.sv.gnu.org/cgit/grep.git/tree/AUTHORS>.

-w表示word regexp,意为只显示完全匹配的行

代码语言:shell复制
[root@iZuf6gxtsgxni1r88kx9rtZ jiangms]# grep -w Nature linux_cmd/science.txt 
Nature Cancer | 10 min read
Nature Cancer | 10 min read
...
Nature | 6 min read

-x:与-w相对应的,还有一个-x,表示 line regexp-w是只单词的完全匹配,而-x指的是整行的完全匹配,如下:

代码语言:shell复制
[root@iZuf6gxtsgxni1r88kx9rtZ jiangms]# grep -x "Nature | 6 min read" linux_cmd/science.txt 
Nature | 6 min read
Nature | 6 min read
Nature | 6 min read
Nature | 6 min read

以上仅列出相对常见的命令参数以及用法,对于其他命令参数还需要大家在实践中遇见或者使用--help来慢慢熟悉。

2 关于正则表达式的说明

其实grep的正则表达式与其他命令的正则表达式几乎一致,比如awkvim啊,其实都是大同小异,不过在这里也详细介绍下:

2.1 基本元字符

单字符:

.: 匹配单个字符

*:匹配0个或者多个字符

^:匹配句首的位置

$:匹配句尾的位置

[]:匹配方括号内的任意字符

< >: 词首词尾符号

():匹配后的标签

:转义字符

复合字符:

[^...]:匹配非方括号内的字符

.*:匹配任意多个字符

示例:

关于. 匹配单个字符

代码语言:shell复制
[root@iZuf6gxtsgxni1r88kx9rtZ linux_cmd]# grep 'n.l' grep_info.txt 
nfl
nbl
nll

仅能匹配含有n[char]l格式的字符,并输出

关于* 匹配0个或多个字符

代码语言:shell复制
[root@iZuf6gxtsgxni1r88kx9rtZ linux_cmd]# grep 'n*l' grep_info.txt 
nfl
nbl
mlb
nl
nll

n*l 可以匹配含有l或者nl或者ncharl字符的字符串

关于^匹配句首位置

代码语言:shell复制
[root@iZuf6gxtsgxni1r88kx9rtZ linux_cmd]# grep '^n' grep_info.txt 
ncaa
nfl
nbl
nl
nll

^n 仅匹配句首为n的行

关于句尾$也是同样的道理,当然也可以同时使用。

关于[] 匹配方括号内的任意字符

代码语言:shell复制
[root@iZuf6gxtsgxni1r88kx9rtZ linux_cmd]# grep 'n[a-g]l$' grep_info.txt 
nfl
nbl

以l结尾,并且仅能匹配含nal、nbl、ncl、ndl、nel、nfl和ngl结尾的字符串。

关于< >匹配词首词尾

代码语言:shell复制
[root@iZuf6gxtsgxni1r88kx9rtZ linux_cmd]# grep '<wonder' grep_info.txt 
hello wonder
hello wonderful
wonders
[root@iZuf6gxtsgxni1r88kx9rtZ linux_cmd]# grep '<wonder>' grep_info.txt 
hello wonder

通过上述例子可以看到<>的作用在于哪里。

2.2 拓展元字符

对于上述基本元字符其实还有一些功能无法实现,此时就需要使用egrep命令来使用拓展正则表达式。具体的元字符如下:

: 匹配一次或多次,请跟基本元字符中的*注意区分

?: 匹配0次或1次,请跟基本元字符中的.注意区分

a|b: 匹配a或者匹配b

{m}:匹配m次前导字符

{m,}: 匹配m次或者m次以上的前导字符

{m,n}:匹配m次到n次范围的前导字符

(): 匹配字符组

示例:

{m,n}表示匹配m到n次范围的前导字符

代码语言:shell复制
[root@iZuf6gxtsgxni1r88kx9rtZ linux_cmd]# egrep '[a-d]{2,}' grep_info.txt 
cba
ncaa
caa
wdwddd
abc-cba

含有a-d的字符,并且连续两个及以上

?表示匹配1次或多次

代码语言:shell复制
[root@iZuf6gxtsgxni1r88kx9rtZ linux_cmd]# egrep 'c?a' grep_info.txt 
hello great
cba
ncaa
caa
abc-cba

c?a表示含有ca或者cca...这种字符串的行

a|b表示匹配a或者匹配b

代码语言:shell复制
[root@iZuf6gxtsgxni1r88kx9rtZ linux_cmd]# egrep 'nbl|nfl' grep_info.txt 
nfl
nbl

请注意拓展正则表达式仅能在命令egrep上使用,如果用在grep上,则没有效果。

3 结论

到此,基本上就介绍完了grep命令的基本用法,本篇尽管不复杂,但是需要记住颇多的命令,倒是对于初学者比较繁琐。而且本文,相较于百度而来的文章的创新点在于将基本的命令行的解释和正则表达式进行的通篇的解读并且加入了自己的理解,能够让读者能够通过这一篇上手grep命令,这是我的文章的初衷。

0 人点赞