要想使用好grep、sed、awk的各种功能,必须把正则表达式了解清楚。


正则表达式分为两类:

    基本正则表达式:BRE

    扩展正则表达式:ERE


基本正则表达式的元字符:

字符匹配:

    .:  匹配任意单个字符;

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

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

        [:digit:],[:upper:],[:lower:],[:alpha:],[:alnum:],[:space:],[:punct:]

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

    *:匹配前面的字符任意次;(0次1次或多次)

    例如:grep "x*y"

        abxy

        xay

        xxxxxxxxxy

        贪婪模式

    .*:任意长度的任意字符

    \?:匹配其前面的字符0或1次;即前面的可有可无

    \+:匹配其前面的字符至少1次

    \{m\}:匹配前面的字符m次;

    \{m,n\}:匹配前面的字符至少m次,至多n次

    \{0,n\}:匹配前面的字符至多n次;

    \{m,\}:匹配前面的字符至少m次;

位置锚定:

    ^:行首锚定:用于模式的最左侧;

    $:行尾锚定:用于模式的最右侧;

    ^PATTERN$:用于模式匹配整行;

    ^$:空行;

    ^[[:apace:]]*$:这个空白可以没有,有任意个都算

    \<\b:词首锚定:用于单词模式的左侧;

    \>\b:词尾锚定:用于单词模式的右侧;

    \<PATTERN\>:匹配整个单词;

分组:

    \(\):将一个或多个字符捆绑在一起,当作一个整体进行处理;

        # grep "\(xy\)\+" grep.txt

        \(xy\)*ab

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

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

        \(ab\+\(xy\)*\):

            \1:ab\+\(xy\)*

            \2:xy

反向引用:引用前面的分组括号中的模式所匹配字符,(而非模式本身)


扩展正则表达式的元字符:

字符匹配:

    .

    []

    [^]

次数匹配:

    *

    ?:0或1次

    +:1次或多次

    {m}:匹配m次

    {m,n]:至少m,至多n次

锚定:

    ^

    $

    \<,\b

    \>,\b

分组:

    ()

    后向引用:\1,\2, ...

或者:

    a|b

    C|cat:C或cat


grep:

Linux上文处理三剑客

grep:文本过滤(模式:pattern)工具;

grep,egrep,fgrep

sed:stream editor,文本编辑工具;

awk:Linux上的实现gawk,文本报告生成器;

grep全称:Global search REgular expression and Print Out the line.


    作用:文本搜索工具,根据用户指定的“模式”对目标文件逐行进行匹配检查:打印匹配到的行;

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

    REGEXP:由一类特殊字符及文本字符所编写的模式,其中有些字符不表示字符字面意义,而表示控制或通配的功能;


语法:

    grep [OPTIONS] PATTERN [FILE...]

常用选项:

    --color=auto:对匹配到的文本着色显示;

    -v:显示不能够被pattern匹配到的行;

    -i:忽略字符大小写;

    -o:仅显示匹配到的字符串

    -q:静默模式,不输出任何信息;(可用echo $?查看)

    -A #:after,显示匹配的后#行

    -B #:beforce,显示匹配的前#行

    -C #:context,前后各#行

    -E:使用ERE,支持扩展的正则表达式

    -h:查询多文件时不显示文件名

    -l:只列出符合匹配的文件名,而不列出具体的匹配行

    -n:列出所有匹配的行,并显示行号

    -s:不显示不存在或无匹配广西的错误信息

    -c:只输出匹配行的数量


示例:

各种选项匹配:

[root@C7-1 ~]# grep root /etc/passwd              #不加任何参数,显示出匹配的行
root:x:0:0:root:/root:/bin/bash
operator:x:11:0:operator:/root:/sbin/nologin
[root@C7-1 ~]# grep -v "root" /etc/passwd         #使用-v参数,显示所有不包括root的各行 
bin:x:1:1:bin:/bin:/sbin/nologin                  
daemon:x:2:2:daemon:/sbin:/sbin/nologin
adm:x:3:4:adm:/var/adm:/sbin/nologin
......以下略
[root@C7-1 ~]# grep -i ROOT /etc/passwd           #使用-i参数,忽略大小写
root:x:0:0:root:/root:/bin/bash
operator:x:11:0:operator:/root:/sbin/nologin
[root@C7-1 ~]# grep -o root /etc/passwd           #使用-o参数,仅显示匹配到的字符串
root
root
root
root
[root@C7-1 ~]# grep -A 2 root /etc/passwd         #使用-A参数,显示匹配的后2行
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
--
operator:x:11:0:operator:/root:/sbin/nologin
games:x:12:100:games:/usr/games:/sbin/nologin
ftp:x:14:50:FTP User:/var/ftp:/sbin/nologin
[root@C7-1 ~]# grep -B 2 root /etc/passwd         #使用-B参数,显示匹配的前2行
root:x:0:0:root:/root:/bin/bash
--
halt:x:7:0:halt:/sbin:/sbin/halt
mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
operator:x:11:0:operator:/root:/sbin/nologin
[root@C7-1 ~]# grep -c root /etc/passwd           #使用-c参数,只显示出匹配行的行数
2
[root@C7-1 ~]# grep -n "root" /etc/passwd         #使用-n参数,显示满足匹配所有行行数
1:root:x:0:0:root:/root:/bin/bash
10:operator:x:11:0:operator:/root:/sbin/nologin

扩展正则、或匹配:

[root@C7-1 tmp]# cat 12                   #查看12文件,abxy和root下面为空行
abxy

xay
xxxxxxy
root

#
#
[root@C7-1 tmp]# grep -n ^$ 12            #使用^$显示出空行所在行号
2:
6:
[root@C7-1 tmp]# grep -v ^$ 12            #排除空行的显示
abxy
xay
xxxxxxy
root
#
#
[root@C7-1 tmp]# grep -E -v "^$|\#" 12    #由于|是扩展正则,需要配合-E使用,排除空行和#的行
abxy
xay
xxxxxxy
root
[root@C7-1 ~]# grep -E "root|nologin" /etc/passwd    #由于|是扩展正则,需要配合-E使用,此行代表显示包含root或nologin的行
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
.....略


实际示例:

1、显示/proc/meminfo文件中以大小S开头的行;(要求:使用两种方式)

[root@C7-1 ~]# grep -i '^s' /proc/meminfo            #方法一,-i忽略大小写,^s以s为开头
[root@C7-1 ~]# grep -i '^s' /proc/meminfo            #方法二

2、显示/etc/passwd文件中不以/bin/bash结尾的行;

[root@C7-1 ~]# grep -v '/bin/bash$' /etc/passwd      #-v参数是排除包含关键字的行

3、显示/etc/passwd文件中ID号最大的用户的用户名;

[root@C7-1 ~]# sort -t: -k3 -n /etc/passwd             #-t:指定分隔符,-k3指定字段,-n以数值大小排序
[root@C7-1 ~]# sort -t: -k3 -n /etc/passwd | tail -1   #上面的命令把最大的排在最后,tail -1显示最后一条数据
bash:x:2019:2019::/home/bash:/bin/bash
[root@C7-1 ~]# sort -t: -k3 -n /etc/passwd | tail -1 | cut -d: -f1   #-d:指明分隔符,-f1指定字段
bash

4、如果用户root存在,显示其默认的shell程序;

[root@C7-1 ~]# grep "^root\>" /etc/passwd        #词首和词尾锚定匹配root
root:x:0:0:root:/root:/bin/bash
[root@C7-1 ~]# id root &> /dev/null && grep "^root\>" /etc/passwd | cut -d: -f7    #id查找,如果root存储,就显示root的默认shell
/bin/bash

5、找出/etc/passwd中的两位或三位数

[root@C7-1 ~]# grep "\<[0-9]\{2,3\}\>" /etc/passwd        #如果不使用\<,\>词首词尾锚定,就有可能会匹配4位中的3位。

6、显示/etc/rc.d/rc.sysinit文件中,至少以一个空白字符开头的且后面存非空白字符的行

[root@C7-1 ~]# grep "^[[:space:]]\+[^[:space:]]" /etc/grub2.cfg  

7、找出“netstat -tan”命令的结果中以'LISTEN'后跟0、1或多个空白字符结尾的行;

[root@C7-1 ~]# netstat -tan | grep "LISTEN[[:space:]]*$"      #空格后面的*$表示结尾有多个空格
[root@C7-1 ~]# netstat -tan | grep "LISTEN[[:space:]]*$"
tcp        0      0 0.0.0.0:22              0.0.0.0:*               LISTEN     
tcp        0      0 127.0.0.1:25            0.0.0.0:*               LISTEN     
tcp6       0      0 :::22                   :::*                    LISTEN     
tcp6       0      0 ::1:25                  :::*                    LISTEN

8、添加用户bash、testbash、basher以及nologin(其shell为/sbin/nologin);而后找出/etc/passwd文件中用户名同shell名的行;

[root@C7-1 ~]# grep "^\([[:alnum:]]\+\>\).*\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
bash:x:2019:2019::/home/bash:/bin/bash

9、显示当前系统root、centos或user1用户的默认shell和UID;

[root@C7-1 ~]# grep -E '^(root|centos|user)\>' /etc/passwd | cut -d: -f1,3,7  #(root|centos|user)这个属于扩展正则表达式,所以要使用egrep或grep -E
root:0:/bin/bash
centos:2008:/bin/bash

10、找出/etc/rc.d/init.d/functions文件中某单词后面跟一个小括号的行(C6上)

[root@C7-1 ~]# grep -E -o "^[_[:alpha:]]+\(\)" /etc/rc.d/init.d/functions
checkpid()
__pids_var_run()
__pids_pidof()
daemon()

11、使用echo输出一绝对路径,使用egrep取出其基名;(基名就是/etc/passwd passwd就是)

[root@C7-1 ~]# echo "/mnt/sdc" | grep -E "[^/]+$"           #行尾的字符串,[^/]除了/斜线的任意内容,+代表这个/至少出现1次
/mnt/sdc
[root@C7-1 ~]# echo "/mnt/sdc" | grep -E -o "[^/]+$"        #sdc是基名
sdc
# echo "/mnt/sdc" | grep -E -o "[^/]+/?$" | cut -d"/" -f1   #以/作为分隔符,来取sdc
[root@C7-1 ~]# echo "/mnt/sdc/" | grep -E "[^/]+/?$"        #万一还带一个/,就用/?可有可无
/mnt/sdc/

进一步地:使用egrep取出路径的目录名,类似于dirname命令的结果

12、找出ifconfig命令结果中1-255之间的数值;

[root@C7-1 ~]# ifconfig | grep -E -o "\<([1-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\>"
192
168
2
127
....略

13、找出ifconfig命令结果中的IP地址

[root@cat ~]# ifconfig eth0
eth0      Link encap:Ethernet  HWaddr 00:0C:29:E0:3C:EC  
          inet addr:192.168.88.66  Bcast:192.168.88.255  Mask:255.255.255.0
          inet6 addr: fe80::20c:29ff:fee0:3cec/64 Scope:Link
....略
[root@cat ~]# ifconfig eth0 | grep "inet addr" | cut -d: -f 2|cut -d" " -f 1  #" "表示分隔符是空格
192.168.88.66