背景
grep命令最初是由美国计算机科学家肯·汤普逊(Ken Thompson)在1974年发明, 为了让用户全局搜索所有匹配的内容并打印它们,所以使用 g/regularexpression/p, 简单地写成 g/re/p( globally search a regular expression and print)。后来也可以解释为"Global Regular Expression Print"(全局正则表达式打印)的首字母缩写。
肯·汤普逊发明grep命令的主要动机是为了提供一种强大而灵活的文本搜索工具,以满足Unix操作系统用户处理文本数据的需求。在当时,Unix系统的用户需要一种能够快速搜索文本文件中特定模式的工具,以便在处理文本数据时能够高效地定位和提取所需的信息。肯·汤普逊意识到,为了提高Unix系统的实用性,需要一种能够灵活处理文本数据的工具,而grep命令的发明正是为了满足这一需求。
格式
grep命令格式较为简单,grep [OPTIONS] PATTERN [FILE/FOLD...],其中 :
-
OPTIONS为选项
-
PATTERN 为搜索模式
-
FILE 为文件名;如果使用-r递归搜索的时候,可以选择某个文件夹( FOLD)
* 注:如果省略 FILE/FOLD,则从标准输入读取内容
参数
本文仅介绍常用参数,如果读者有兴趣了解更多参数,请运行“man grep”或者“grep --help”查看。
-
-i:ignore 忽略大小写
-
-c:count 取行数
-
-w: word 匹配单词
-
-E:extended 正则
-
-P:perl 正则
-
-l:list 列出包含关键字的文件
-
-A:after 取出匹配行以及后续行
-
-B:before 取出匹配行以及前续行
-
-C:取出匹配行的上下行
-
-R:在目录下搜索,比如grep 'abc' ./,表示在当前目录下所有文件进行查找
-
-v:invert 排除
-
-n:number 显示行号
-
-o:only matching 只显示匹配到的内容
-
-r:recursive 递归式搜索
grep的参数是比较多并且复杂的,但无论如何,grep命令的本质还是在于“文件内容的搜索”,而不是“文件名的搜索”。
返回值
-
0 :表示成功
-
1 :表示所提供的文件无法找到匹配的pattern
-
2 :表示查找地点不对
实战
-
搜索出当前系统下“nologin”的用户信息
grepnologin/etc/passwd
*注:grep只是将包括"nologin"关键字的整行给输出来,而不考虑"nologin"在该行的位置。也就是说,如果有一个用户叫做"nologin1"但是它又是可以login的,那通过上述grep命令,同样也能获取到该行(而这并非一个有效的行)
所以,如果要准确查询出系统下“nologin”的用户信息,需要保证"nologin"出现在行尾,对上述命令进行改进后:
grep'nologin$'/etc/passwd
*注:grep搜索时,^表示开头,$表示结尾
-
搜索出当前文件夹下有哪些子文件夹
ls-l|grep^d
-
搜索出系统中ifconfig配置的ip信息
ifconfig|grep-winet
*注:如果使用了-w选项,那有单独inet关键字的行会被搜索出来,但是inetabc的行,不会被匹配
同样,如果为了更精确搜索配置的ip信息,应该以每行开头为“多个空格加inet”这样的形式进行检索,命令如下:
ifconfig|grep'^[]*inet'
*注:上述命令中,[ ]代表一个空格字符,*表示重复前面0个或者多个;如果[abc]*,表示“
任意abc字符中的一个”重复0次或者多次,所以[abc]*既可以匹配a或者b或者c,也可以匹配abc或者aaa或者abcabc,同样也能匹配aabccc
-
搜索出系统中ifconfig配置的ip信息,以及对应的网卡名称
为了检索出上述内容,用户需要首先了解ifconfig输出的信息:在正常ifconfig的输出中,inet上一行的内容,即是对应的网卡名称。
ifconfig|grep-B1'^[]*inet'
*
注:如果-B2,代表将匹配行上面2行同时打印出来
-
检索出/proc/cpuinfo中,关键字“processor”在文件中的行号
grep-n'processor'/proc/cpuinfo
*注:上述输出结果中,左右绿色部分,即为关键字在源文件中的行号
同样,如果需要统计关键字“processor”在文件/proc/cpuinfo中一共出现了多少次,可以运行如下命令统计:
grep-c'processor'/proc/cpuinfo
*注:如上命令为统计x86系统中处理器的个数
-
在/proc/cpuinfo中检索出包含关键字“processor”往下5行的内容,但需要排除掉有关键字“model”的行
首先,通过-A5可以搜索出关键字往下5行信息,grep -A5 'processor' /proc/cpuinfo
如果需要再排除掉含有关键字“model”的行,通过管道进行二次搜索即可:
grep-A5'processor'/proc/cpuinfo|grep-v'model'
-
在/var/log下,针对所有messages的log,搜索出包含关键字fail的文件(忽略fail的大小写)
grep -i -l 'fail' /var/log/messages*
*注:如果需要在多个文件中搜索,可以grep 'xxx' file1 file2,或者grep 'xxx' file*,或者grep 'xxx' *file
-
在/var/log下,针对所有messages的log,搜索出包含关键字fail或者error的内容(忽略大小写)
grep-i-E'fail|error'/var/log/messages*
*注:-E代表扩展正则,通常情况下有如下5种扩展:
-
+:重复1次或者多次前面的字符,比如grep -E 'ab+c' file,表示在file中搜索包括1个a,多个b,并且跟上1个c的内容
-
?:重复0次或者1次前面的字符,比如grep -E 'ab?c' file, 表示在file中搜索包括1个a,0个b或者1个b,并且跟上1个c的内容
-
|:用“或”的方式查找多个符合的字符串,比如grep -E 'fail|error' file
-
():作为某个特定组合,比如说grep -E 'level=(fail|error)' file,表示在file中查找包括level=fail或者level=error的内容。如果去掉括号grep -E 'level=fail|error' file,代表查找匹配level=fail或者一行中单独匹配error的内容
-
{m,n}/{m,}/{,n}/{n}:表示重复m到n次(闭区间)/大于等于m次/小于等于n次/n次,在不用-E参数时,所有这部分花括号用法得两侧加反斜线:\{m,n\}
-
在/var/log/secure*文件中,统计出最近通过ssh访问本服务器的ip以及端口信息
首先,如果简单查看/var/log/secure文件,可以发现根据关键字"Accepted password for root from"可以获取到粗略信息如下:
但如果只是想获取到访问本服务器的ip以及端口信息(ip与端口不相同),此时就需要进行正则匹配,同时将匹配的内容给输出来,而不显示行中其它信息:
grep'Acceptedpasswordforrootfrom'secure*|grep-o'[0-9\.]*port[0-9]*'
*注:-o是仅仅将匹配的内容显示出来(而不显示整行)。通过-o加正则的方式,可以获取出被grep匹配到的内容。
-
在当前文件夹以及子文件夹下搜索内容包括'error'的信息
有时候系统会将过期日志新建一个子文件夹,并remove到该文件夹下去,如果某天用户希望找到当前文件夹以及子文件夹下的文件内容包括'error'的相关信息,可以通过-r参数来实现:
grep-r'error'./
*注:如果执行grep -r 'error' ./*.log,仅仅代表在当前目录下*.log文件中搜索'error'关键字的行
-
取出Oracle的ddl中,普通索引或者unique索引的列名中包括'#'的相关行?(假设索引定义都在一行)
首先,Oracle的ddl信息如下:
尝试一:grep -E 'CREATE INDEX|CREATE UNIQUE INDEX' ora_ddl.sql | grep '#'
分析,该尝试可能存在问题,如果索引名带'#',也会搜索出来
尝试二:grep 'CREATE INDEX|CREATE UNIQUE INDEX' ora_ddl.sql -E | grep -P ‘\(.+?\#.+?\)’
分析,上述语句首先将索引或者unique索引行搜索出,再通过-P的perl正则,对索引定义的括号"()"内字段名进行匹配,从而准确匹配出索引列中包括'#'的内容
尝试三:grep -P 'CREATE\s+(UNIQUE\s+){0,1}INDEX.+?\(.+?\#.*?\)' ora_ddl.sql
分析,上述语句通过一次grep,直接准确匹配出索引或者unique索引字段中包括'#'的内容
*注:perl正则匹配中
-
. 代表任意字符
-
\s代表空格或者制表符
-
()中内容代表某个整体
-
+代表匹配一次或者多次
-
*代表匹配0次或者多次
-
.+?代表匹配到最近的对象(非贪婪)
-
{1,5}代表匹配1-5次(非1次跟5次,而是1次,2次,3次…5次)
总结
grep命令用来在文件中搜索匹配的内容,既可以在当前文件夹搜索,也可以在当前文件夹以及子文件夹搜索。既可以搜索一个文件,也可以搜索多个文件。grep提供了多种搜索的方式,既可以忽略大小写,也可以全词检索,还可以使用普通正则或者扩展正则再或者perl的正则。并且在输出结果的时候,既可以输出匹配的内容/文件名,也可以输出对应的行号或者匹配内容的总个数,还可以输出匹配内容的前后多少行,或者干脆输出不匹配的部分。在使用正则进行匹配的时候,常见的shell正则grep都能支持,如果有进一步的正则扩展,请使用-E参数。但请注意grep没办法对某一列的内容进行匹配而后输出,除非使用一个很长的正则一直匹配到该列内容。所以很多时候grep的搜索会有不精确性,需要用户在搜索的基础上进行二次过滤,或者使用更加准确的搜索pattern。
总之,grep是Linux上强大的文件检索工具,用户几乎可以使用grep一个命令检索到所需要的各种信息,当然,很多时候还需要使用管道进行多重grep。