Linux文件处理三剑客之grep

2023年 11月 27日 73.7k 0

背景

    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”的用户信息

grep nologin /etc/passwd

    

   
*注:grep只是将包括"nologin"关键字的整行给输出来,而不考虑"nologin"在该行的位置。也就是说,如果有一个用户叫做"nologin1"但是它又是可以login的,那通过上述grep命令,同样也能获取到该行(而这并非一个有效的行)

    所以,如果要准确查询出系统下“nologin”的用户信息,需要保证"nologin"出现在行尾,对上述命令进行改进后:

grep 'nologin$' /etc/passwd

   
*注:grep搜索时,^表示开头,$表示结尾

  •     搜索出当前文件夹下有哪些子文件夹

ls -l | grep ^d

    

    

  •     搜索出系统中ifconfig配置的ip信息

ifconfig | grep -w inet

    

   
*注:如果使用了-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 'Accepted password for root from' 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 'CREATEs+(UNIQUEs+){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。

相关文章

服务器端口转发,带你了解服务器端口转发
服务器开放端口,服务器开放端口的步骤
产品推荐:7月受欢迎AI容器镜像来了,有Qwen系列大模型镜像
如何使用 WinGet 下载 Microsoft Store 应用
百度搜索:蓝易云 – 熟悉ubuntu apt-get命令详解
百度搜索:蓝易云 – 域名解析成功但ping不通解决方案

发布评论