shell,Linux

GNU Grep与正则表达式

grep简介

grep:Global search REgular expression and Print out the line,Linux文本处理三剑客(grepsedawk)之一,是一款文本过滤工具,在一个或多个输入文件中搜索包含与指定模式(pattern)匹配的行。默认情况下,grep输出匹配的行。当我们需要快速定位查找文本(通常是配置文件)中我们需要的内容时,使用grep命令绝对是最有效的处理方式之一。原因就在于grep可以配合包括“管道”、“正则表达式(Regular Expression)”等命令完成我们想要的关键字筛选过滤功能。 grep在大部分的 Linux 发行版中都是默认有安装


<center>man grep</center>

  • 模式

    由正则表达式字符及文本字符所编写的过滤条件
  • 正则表达式

    由一类特殊字符及文本字符所编写的模式,其中有一些字符不表示字符字面意义,而表示控制或通配的功能。支持程序有grep,sed,awk,vim,less,nginx,varnish……它分为基本正则表达式和扩展正则表达式两类,用于grep中,则grep后支持基本正则表达式,grep -E或egrep后支持扩展正则表达式
    

正则表达式分为两类

  • 基本正则表达式:BRE
  • 扩展正则表达式:ERE

    egrep, grep -E
    

grep语法

  • grep [OPTIONS] PATTERN [FILE...]
  • grep [OPTIONS] [-e PATTERN | -f FILE] [FILE...]
-A NUM, --after-context=NUM
       除了显示符合查找的那一行之外,并显示该行之后的内容

-a, --text
      不忽略二进制数据

-B NUM, --before-context=NUM
       除了显示符合查找的那一列之外,并显示该列之前的内容
-b, --byte-offset
       在显示符合查找的那一列之前,标示出该列第一个字符的位编号
--binary-files=TYPE
       如果文件的前几个字节表明该文件包含二进制数据,则假定该文件的类型为TYPE。
       默认情况下,TYPE是二进制,grep通常输出要么是二进制文件匹配的单行消息,要么就是没有消息不配
       如果TYPE不匹配,则grep假定二进制文件不匹配;这相当于-I选项
       如果TYPE是文本,则grep将二进制文件处理为文字; 这相当于-a选项
--colour[=WHEN], --color[=WHEN]
       使用GREP_COLOR环境变量中的标记匹配的字符串,可以是'never','always'或'auto',例如--color = always,默认情况下,匹配的文本将显示为红色。如果使grep匹配多个字符串,则所有匹配都将着色,一个例外是正则表达式^(匹配每一行的开头),一行开头没有长度所以会不着色。所以返回所有的行和颜色只匹配: egrep --color=always '^|string1|string2'
       CentOS 6 与CentOS 7的区别:CentOS 7上默认已经定义别名`alias grep='grep --color=auto'`来高亮显示匹配到的字符串,CentOS 6没有定义

-C NUM, --context=NUM
         除了显示符合范本样式的那一列之外,并显示该列之前后的内容

-c, --count
        计算符合范本样式的列数

-D ACTION, --devices=ACTION
       如果输入文件是设备,FIFO或套接字,请使用ACTION处理它。默认情况下,会读取ACTION,这意味着设备的读取就像它们一样普通文件。如果跳过ACTION,则会跳过设备

-d ACTION, --directories=ACTION
       如果输入文件是目录,请使用ACTION处理它。默认情况下,读取ACTION,这意味着读取目录就像它们一样是普通文件。如果跳过ACTION,则会跳过目录。如果ACTION是递归的,grep会递归地读取每个目录下的所有文件; 这个相当于-r选项

-E, --extended-regexp
       扩展为正则表达式

-e PATTERN, --regexp=PATTERN
       指定字符串做为查找文件内容的范本样式

-F, --fixed-strings
       将范本样式视为固定字符串的列表

-f FILE, --file=FILE
        指定范本文件,其内容含有一个或多个范本样式,让grep查找符合范本条件的文件内容,格式为每列一个范本样式

   -G
   --basic-regexp
       将范本样式视为普通的表示法来使用

-H, --with-filename
       在显示符合范本样式的那一列之前,表示该列所属的文件名称
-h, --no-filename
       在显示符合范本样式的那一列之前,不标示该列所属的文件名称

--help
      输出简短的帮助信息

-I
      处理二进制文件,就好像它不包含匹配数据一样; 这时相当于--binary-files =不匹配选项

-i, --ignore-case
      忽略字符大小写的差别

-L, --files-without-match
      列出文件内容符合指定的范本样式的文件名称
-l, --files-with-matches
      列出文件内容不符合指定的范本样式的文件名称

-m NUM, --max-count=NUM
      NUM匹配行后停止读取文件。 如果输入是常规文件的标准输入,并且输出NUM匹配行,则grep确保标准输入在退出之前位于最后一个匹配行之后,而不管是否存在尾随上下文行。 这使得呼叫过程能够恢复搜索。 当grep在NUM个匹配行后停止时,它会输出任何尾随上下文行。 如果还使用-c或--count选项,则grep不会输出大于NUM的计数。 当还使用-v或--invert-match选项时,grep在输出NUM个不匹配行后停止

-n, --line-number
     使用输入文件中的行号为每行输出添加前缀

-o, --only-matching
      只输出文件中匹配到的部分

--label=LABEL
      显示输入实际来自标准输入,作为来自文件LABEL的输入。这对于像zgrep这样的工具特别有用,例如 gzip -cd foo.gz |grep --label=foo something

--line-buffered
      使用行缓冲,它可以是性能压力

-P, --perl-regexp
       将PATTERN解释为Perl正则表达式。`grep -P可能会警告未实现的功能`

-q, --quiet, --silent
       不在标准输出上写任何东西
-R, -r, --recursive
       递归读取每个目录下的所有文件; 相当于'-d recurse'选项。并非所有grep实现都支持-r,并且在这些实现中,链接的行为可能不同

--include=PATTERN
       在仅搜索匹配文件的目录中递归

--exclude=PATTERN
       目录中的递归跳过文件匹配模式

-s, --no-messages
       不显示错误信息

-U, --binary
       将文件视为二进制文件

-u, --unix-byte-offsets
        报告Unix样式的字节偏移

-V, --version
       将grep的版本号打印到标准错误

-v, --invert-match
       反转匹配,选择不匹配的行

-w, --word-regexp
       仅选择包含构成整个单词的匹配项的行

-x, --line-regexp
       仅选择与整行完全匹配的匹配项。

-y
      此参数效果跟“-i”相同
-Z, --null
       输出零字节(ASCII NUL字符),而不是通常在文件名后面的字符

基本正则表达式元字符

  • 字符匹配
    两个::之间没用空格

  • 次数匹配
    匹配次数用于要指定次数的字符后面,用于指定前面的字符要出现的次数

  • 位置锚定
    对特殊位置进行定位

模式匹配整行

  • ^$: 空行,不包含有空格的行
  • ^[[:space:]]*$: 空行,但是包含有空格的行

分组及后向引用

分组是指将一个或多个字符捆绑在一起,当作一个正题处理。在基本正则表达式中,()需要用\来转义,其符号为:\(\),用法如下:

  • 分组:括号中的模式匹配到的内容会被正则表达式引擎记录于内部变量中,这些变量的命名方式为:\1, \2, ..., \n

    从左侧起,第一个括号以及与之匹配的右括号之间的模式所匹配到的字符,如:

  \(ab\+\(xy)*\)\1表示ab\+\(xy\)*, \2表示xy

  \(string1\+\(string2\)*\)

    \1表示string1\+\(string2\)*

    \2 表示string2

  • 后向引用:引用前面的分组括号中的模式所匹配到的字符,而非模式本身。

使用示例

如下所有示例皆以CentOS 7为例

  • 找出/etc/passwd文件中usernameshell相同的的行
[root@node04 ~]# grep "^\(.*\):.*\<\1$" /etc/passwd
sync:x:5:0:sync:/sbin:/bin/sync
shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
halt:x:7:0:halt:/sbin:/sbin/halt
  • 取出网卡接口ens33上的IPv4地址
[root@node04 ~]# ip addr show dev ens33 | grep -o "\([[:digit:]]\{1,3\}\.\)\{3\}[[:digit:]]\{1,3\}" | head -1
172.16.183.157
  • 取出/etc/rc.d/init.d/functions的基名
[root@node04 ~]# ls /etc/rc.d/init.d/functions | grep -o "[^/]\+\?$"
functions
  • 显⽰/proc/meminfo⽂件中以⼤⼩s开头的⾏
[root@node04 ~]# grep -i ^s.* /proc/meminfo
SwapCached:            0 kB
SwapTotal:             0 kB
SwapFree:              0 kB
Shmem:             11780 kB
Slab:              46088 kB
SReclaimable:      18356 kB
SUnreclaim:        27732 kB
  • 找出/etc/passwd文件中的两位或三位数
[root@node04 ~]# grep "\b[[:digit:]]\{2,3\}\b" /etc/passwd
  • 显⽰CentOS7的/etc/grub2.cfg⽂件中,⾄少以⼀个空⽩字符开头的且后⾯有⾮空⽩字符的⾏
[root@node04 ~]# grep  "^[[:space:]]\+[^[:space:]]" /etc/grub2.cfg
  • 显⽰rootlus4lm0x三个⽤户的UID和默认shell
[root@node04 ~]# grep "^\(root\|lu\|s4lm0x\)" /etc/passwd | cut -d: -f1,7 --output-delimiter=" "
  • 找出/etc/rc.d/init.d/functions⽂件中⾏⾸为某单词(包括下划线)后⾯跟⼀个⼩括号的⾏
[root@node04 ~]# grep -E "^[[:alpha:]_]+\(\)" /etc/rc.d/init.d/functions
  • 找出ldd /usr/bin/python命令的结果中文件路径
[root@node04 ~]# ldd /usr/bin/python | grep -o "/[^[:space:]]\+"
  • 输出系统cpu数量
[root@node04 ~]# grep "processor" /proc/cpuinfo | wc -l
  • 打印file1中缺少的file2行
[root@node04 data]# grep -vxFf fstab fstab2
  • 在当前目录下递归查找包含passwd字符串的行,并连同行号打印
    AWD攻防环境中,可能需要快速定位数据库连接密码,此时个人觉得该命令很实用
[root@node04 data]# grep -nr "passwd" .

扩展正则表达式元字符

  • 字符匹配
      []: 匹配指定范围内的任意单个字符

  [^]: 匹配指定范围外的任意单个字符

  • 次数匹配
      *: 任意词

  ?: 0次或1次
  +: 至少1次
  {m}: 精确匹配m次
  {m,n}: 至少m次,至多n次
  {m,}: 至少m次
  {0,n}: 至多n次

  • 锚定
      扩展正则表达式的锚定位置与基本正则表达式相同
  • 分组
      (): 用()括起来表示引用的内容,无需转义
  • 后向引用
      1, 2, 3, ...
  • 或者
      a|b: a或者b

  (Y|y)es: Yes或者yes

扩展正则表达式使用语法

  • grep -E [ PATTERN ] [FILE...]
  • egrep [ PATTERN ] [FILE...]

使用示例

  • 取出/etc/sysconfig/network-scripts基名
[root@node04 data]# echo "/etc/sysconfig/network-scripts" | egrep -o "[^/]+/?$"

参考

grep man帮助

微信扫一扫,向我赞赏

微信扫一扫,向我赞赏

微信扫一扫,向我赞赏

支付宝扫一扫,向我赞赏

回复

This is just a placeholder img.