一、基本概念

正在表达式:正则表达式是对字符串操作的一种逻辑公式,就是用事先定义好的一些特定字符、及这些特定字符的组合,组成一个“规则字符串”,这个“规则字符串”用来表达对字符串的一种过滤逻辑。

grep(global search regular expression(RE) and print out the line):文本搜索工具,根据用户指定的文本模式对目标文件进行逐行搜索,显示能够被模式所匹配到的行(可以看成一个文本过滤器)

egrep:使用扩展正则表达来构建模式,即grep -E

fgrep: fast, 不解析正则表达式,即grep –F

元字符:不表示字符本身的意义,用于额外功能性的描述

二、grep的使用方式

格式:

grep [OPTIONS] PATTERN [FILE...]

eg.# grep "root" /etc/passwd

常用选项:

-E:使用扩展正则表达来构建模式

-F:使用不解析正则表达式构建模式

-i:不区分字符大小写, ignore-case

-v:反向,显示不能被模式所匹配到的行

-o:仅显示被模式匹配到的字串,而非整行

-A #:匹配到的行和它下面的#行

-B #:匹配到的行和它上面的#行

-C #:匹配到的行和紧挨着它的#行

--color:指定被模式匹配到字符的颜色,参数选项有never,always和auto

标准正在表达式的元字符:
1、字符匹配:

.:任意单个字符

[[email protected] ~]# grep --color=auto "ro.t" /etc/passwd
root:x:0:0:root:/root:/bin/bash
operator:x:11:0:operator:/root:/sbin/nologin

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

[0-9], [[:digit:]]:数字字符
[a-z], [[:lower:]]:小写字符
[A-Z], [[:upper:]]:大写字符
[[:alpha:]]:大小写字符
[[:alnum:]]:数字和大小写字符
[[:space:]]:空白字符
[[:punct:]]:标点符号字符

Linux文本处理工具之grep、egrep和fgrep

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

Linux文本处理工具之grep、egrep和fgrep

2、次数匹配:用来指定匹配其前面的字符的次数

*:前面的字符任意次

Linux文本处理工具之grep、egrep和fgrep

注:*前字符的任意次

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

Linux文本处理工具之grep、egrep和fgrep

\?:前面的字符0次或1次

Linux文本处理工具之grep、egrep和fgrep

注:grep模式采用贪婪模式,即尽可能的长的去匹配字符;

\{m\}:匹配m次

\{m,n\}:匹配最少m次,最多n次

\{m,\}:至少m次;

\{0,n\}:至多n次;

Linux文本处理工具之grep、egrep和fgrep

3、位置锚定:用于指定字符出现的位置

^:锚定行首

eg. ^Char

$: 锚定行尾

eg. char$

^$:空白行

\<char:锚定词首,\bchar

char\>:锚定词尾,char\b

4、分组:

\(\)

eg. \(ab\)*xy

引用:

\1:后向引用,引用前面的第一个左括号以及与之对应的右括号中的模式所匹配到的内容

\2:后向引用,引用前面的第二个左括号以及与之对应的右括号中的模式所匹配到的内容

...

eg. \(a.b\)xy\1: a6bxya6b

Linux文本处理工具之grep、egrep和fgrep

注:匹配那一次刚好匹配的引用,前后字符串一模一样

标准正在表达式的元字符:

字符匹配:

.:任意单个字符

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

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

次数匹配:

*:匹配其前面的字符任意次;

?:匹配其前面的字符0或1次;

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

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

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

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

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

锚定:

^:行首

$:行尾

\<, \b:词首

\>, \b:词尾

分组:

():分组

|:或者, ac|bc,表示ac或bc,或者整个字符串

eg. grep -E "con(C|c)at"

conC或cat

conCat或concat

三、强化练习

实验环境:

硬件:Thinkpad T430 I5-3320M 4GB RAM 500GB HDD

虚拟机:10.0.2 build-1744117

操作系统:CentOS 6.5

1、显示/proc/meminfo文件中以大小写s开头的行;

# grep "^[sS]" /proc/meminfo

2、取出默认shell为非bash的用户;

# grep -v "bash$" /etc/passwd | cut -d: -f1

3、取出默认shell为bash的且其ID号最大的用户;

# grep "bash$" /etc/passwd | sort -n -t: -k3 | tail -1 | cut -d: -f1

4、显示/etc/rc.d/rc.sysinit文件中,以#开头,后面跟至少一个空白字符,而后又有至少一个非空白字符的行;

# grep "^#[[:space:]]\{1,\}[^[:space:]]\{1,\}" /etc/rc.d/rc.sysinit

5、显示/boot/grub/grub.conf中以至少一个空白字符开头的行;

# grep "^[[:space:]]\{1,\}[^[:space:]]\{1,\}" /boot/grub/grub.conf

6、找出/etc/passwd文件中一位数或两位数;

# grep --color=auto "\<[0-9]\{1,2\}\>" /etc/passwd

7、找出ifconfig命令结果中的1到255之间的整数;

# ifconfig | grep -E --color=auto "\<([1-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\>"

8、查看当前系统上root用户的所有信息;

# grep "^root\>" /etc/passwd

9、添加用户bash和testbash、basher,而后找出当前系统上其用户名和默认shell相同的用户;

# grep --color=auto "^\([[:alnum:]]\{1,\}\)\>.*\1$" /etc/passwd

10、找出netstat -tan命令执行的结果中以“LISTEN”或“ESTABLISHED”结尾的行;

# netstat -tan | grep -E --color=auto "(LISTEN|ESTABLISHED)[[:space:]]*$"

11、取出当前系统上所有用户的shell,要求:每种shell只显示一次,且按升序显示;

# cut -d: -f7 /etc/passwd | sort -u

12、写一个脚本,分别统计/etc/rc.d/rc.sysinit、/etc/init.d/functions和/etc/fstab文件中各自以#开头的行的行数,以及空白行的行数;

#!/bin/bash
for file in /etc/rc.d/rc.sysinit /etc/init.d/functions /etc/fstab;do
    bashline=`grep -E --color=auto "^#" $file | wc -l`
    spaceline=`grep -E "^#$" $file | wc -l`
    echo "$file has $bashline , $file has $spaceline"
done

13、写一个脚本,分别复制/etc/rc.d/rc.sysinit、/etc/init.d/functions和/etc/fstab文件至/tmp目录中,文件名为原名后跟上当前的日期组成; (例如第一个文件复制后的名称为/tmp/rc.sysinit-2-14-02-16;)

#!/bin/bash
for path in /etc/rc.d/rc.sysinit /etc/init.d/functions /etc/fstab;do
        fileName=`basename $path`
        cp $path /tmp/$fileName`date +-%y-%m-%d`
done

14、写一个脚本

显示当前系统上所有默认shell为bash的用户的用户名、UID以及其在/etc/passwd文件中的行号;

#!/bin/bash
cat -n /etc/passwd | grep --color=auto "bash$" | cut -d: -f1,3

挑战题:写一个模式,能匹配真正意义上的IP地址;(1.0.0.1--223.255.255.254)

#grep -E --color=auto "\<([1-9]|[1-9][0-9]|1[0-9]{2}|2[0-2][0-3])\>(.\<([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-5][0-5])\>){2}.\<([1-9]|[1-9][0-9]|1[0-9][0-9]|2[0-5][0-4])\>"

扩展:写一个脚本,判断用户输入的IP地址是否合法

#!/bin/bash
read -p "Enter a IP Address:" ipAddress
if [[ -n `echo $ipAddress | grep -E "\<([1-9]|[1-9][0-9]|1[0-9]{2}|2[0-2][0-3])\>(.\<([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-5][0-5])\>){2}.\<([1-9]|[1-9][0-9]|1[0-9][0-9]|2[0-5][0-4])\>"` ]];then
echo "This is a valid ip address!"
else
echo "This is a invalid ip address!"
fi