Linux奉行“一切皆文件”的设计准则。而文本文件占相当大的比重,比如比较重要的配置文件基本都是文本格式的文件。所以如何高效去处理文本文件变得十分重要。接下来介绍一下江湖上广为流传的擅长文本处理的三个“大侠”其中的两个,它们就是grep和sed。grep擅长“千万文本行中寻目标”,而sed则是“每行千变万化合你心”。

 

一、grep

    grep全称Global searchREgular expression and Print put the line.是一个文本搜索工具。

工作原理:grep可以根据用户指定的“模式”对目标文本逐行进行匹配检查,打印匹配到的行;此处的“模式”指的是由正则表达式的元字符及文本字符所编写出的过滤条件;

grep的分类: 

        1、grep: 基本正则表达式;-E(表示支持扩展正则表达式),-F(不支持扩展正则表达式)

        2、egrep:扩展正则表达式;-G(表示支持基本正则表达式),-F(不支持扩展正则表达式)

        3、fgrep: 不支持正则表达式;-E(表示支持扩展正则表达式),-G(支持基本正则表达式)

  注:1、此处fgrep不能支持正则表达式来编写模式,只支持纯文本的模式,故用途不大,不做讲解。

               但如果是不需要正则表达式来编写模式时,用fgrep会比grep效率更高。

              2、关于基本正则表达式和扩展正则表达式会分别在grep命令和egrep命令中给出解释。

(1)grep命令

    使用格式:grep [OPTIONS]PATTERN [FILE...]

                      grep [OPTIONS] [-e PATTERN | -f FILE] [FILE...]

    选项:

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

                 -i:ignorecase,忽略字符的大小写

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

                 -v,--invert-match:仅显示没有匹配到字符串的行

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

                 -q,--quiet,--silent:静默模式,匹配到与否都不显示。

                -A num:after,显示匹配到的行及后num行

                -B num:before,显示匹配到的行及其前num行

                -C num:context,显示匹配到的行及其前后各num行

                -e  PATTERN:表示匹配多个模式,-e 多次使用,每一个 -e 后跟一个模式

                -f  FILE:将模式写在文件中,然后可用-f 读入文件中写入的模式进行匹配查找。

    

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

       1、字符匹配

        .  : 匹配任意单个字符   

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

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

            [:digit:](表示匹配数字0~9中的一个)

            [:lower:](表示匹配所有小写字母中的一个)

            [:upper:](表示匹配所有大写字母中的一个)

            [:alpha:](表示匹配所有字母中的一个)

            [:punct:](表示匹配标点符号中的一个)

            [:space:](表示匹配空白字符)

            [:alnum:](表示匹配所有字母和数字)

             注意:以上的范围实际使用时要再加中括号(例如[[:alpha:]]和[^[:alpha:]])

       2、匹配次数:用在要指定其出现次数的字符的后面,用于限制其前面字符出现的次数;

                    *:匹配起前面的字符任意次:0,1,多次;

                              例如:grep"x*y"

                                     abxy,aby,xxxxxy,yab都匹配

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

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

                   \+:匹配其前面的字符1次或多次;即前面的字符出现至少一次;

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

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

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

                  \{m,\}:至少m次     

       3、位置锚定

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

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

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

        ^$:空白行;

        ^[[:space:]]*$:空行或包含空白字符的行

        \<或\b:词首锚定,用于单词模式的右侧

        \>或\b:词尾锚定,用于单词模式的左侧

            单词:非特殊字符组成的连续字符(字符串)都称为单词;

       4、分组和引用

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

        分组括号中的模式匹配到的内容会被正则表达式引擎自动记录于内部的变量中,这些

        变量为:

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

          符;

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

          符;

            ..

            ..

            ..

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

            \1,\2...可作后向引用:引用前面的分组括号中匹配到的模式

示例一:

1、显示/etc/passwd文件中不以/bin/bash结尾的行
~]# grep -v "/bin/bash$" /etc/passwd
2、找出/etc/passwd文件中两位数或者三位数
~]# grep "\<[0-9]\{2,3\}\>" /etc/passwd
3、找出/etc/rc.d/rc.sysinit中,以至少一个空白字符开头,且后面跟非空白字符的行;
~]# grep "^[[:space:]]\+[^[:space:]]" /etc/rc.d/rc.sysinit
注:此处的 + 前要用转义符 \ 
4、找出"netstat -tan"命令的结果中以‘LISTEN’后跟0、1或多个空白字符的结尾的行;
~]# netstat -tan | grep "LISTEN[[:space:]]*$"
5、后向引用(对于一文本文件中内容如下)
He loves his lover.
He likes his lover.
She likes her liker.
She loves her liker.
~]# grep "\(l..e).*\1" file ----> 此命令利用后向引用可以找出前后一致的行
He loves his lover.
She likes her liker.

二、egerp (支持使用扩展正则表达式来编写模式,等同于grep -E)

    使用格式:egrep [OPTIONS]PATTERN [FILE...]

    选项:

            -i:ignorecase,忽略字符的大小写

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

           -v,--invert-match:仅显示没有匹配到字符串的行

           -q,--quiet,--silent:静默模式,匹配到与否都不显示。

           -A num:after,显示匹配到的行及后num行

           -B num: before,显示匹配到的行及其前num行

           -C num: context,显示匹配到的行及其前后各num行

           -G:表示支持基本正则表达式

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

 1、字符匹配

       .   : 匹配任意单个字符   

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

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

 2、次数匹配

       *  : 匹配其前任意次,0,1,或多次;

       ?  :匹配其前字符0次或1次,即表示其前的字符可有可无

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

      {m}  : 匹配其前字符至少m次

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

      {0,n} :至多n次

      {m,} : 至少m次

 3、位置锚定

      ^  : 行首锚定

      $  : 行尾锚定

      \<或\b: 词首锚定,用于单词模式的右侧

      \>或\b: 词尾锚定,用于单词模式的左侧

     注:此处用法和基本正则表达式一致,请参阅上面。

 4、分组及引用

     (): 分组;括号里的模式匹配到的字符会被记录到正则表达式引擎内的内部变量中

      后向引用: \1,\2(同基本正则表达式)

      表示“或者”的意思:| 

        例1:a|b:a或者b

        例2:C|cat:C或cat

        例3:(c|C)at:cat或Cat

     注:一般和分组一起用,如例3.

示例二

1、找出/proc/meminfo文件中,所有以大写或小写S开头的行。
~]# grep -i "^s" /proc/meminfo
~]# grep "^[s|S]" /proc/meminfo
~]# egrep "^(s|S)" /proc/meminfo
2、显示当前系统上root、centos、user1用户的相关信息
~]# egrep "^(root|centos|user1)\>" /etc/passwd
3、找出/etc/rc.d/init.d/functions文件中某单词后面跟一个小括号的行(即找出所有函数)
~]# egrep  "[_[:alnum:]]+\(\)" /etc/rc.d/init.d/functions
4、找出ifconfig命令结果中的1-255之间的数值;
~]# ifconfig | egrep "\<([1-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\>"

  

  总结:扩展正则表达式比基本正则表达式最大的区别就在于不用加转义符,以及多了一个表示“或者”含义的元字符。总的来说正则表达式的元字符不多,但是灵活应用就会变得非常强大。举个例子,读者可以根据示例二中的第4个例子来得出ip地址的匹配模式。另外当你得出ip地址你会发现,这是一个很笨的方式。关于ip地址的正则表达式匹配方式还有更为简洁的方式来表述,读者可以从此入手,来慢慢体会正则表达式的强大。

 

二、sed (Stream EDitor,流编辑器)

  

工作原理:将目标文本中被模式匹配到的行复制一份在内存中自己的创建的缓冲区(模式空间)进行编辑操作,不会影响原来的文件。每处理一行就将被处理过(除了删除处理)这行的文本输出至标准输出(stdout)。目标文件中不能被模式匹配的行默认被输出到标准输出。

另外sed还会在内存中创建一个保持空间,编辑完的文本可以存放在保持空间中。可以和模式空间进行内容互换,完成以下高级编辑操作。


                           

sed命令

    使用格式:sed [OPTION]...{script} [input-file]...

                注意:sed可以一次处理多个文件。

                       script:由地址定界和编辑命令组成。

  常用选项:   

-n:仅被模式匹配的行编辑后输出

-e script, --expression=script:多点编辑;可以同时给出多个处理。

~]#sed -e 's@^#[[:space:]]*@@' -e '/^UUID/d' /etc/fstab
#这条命令表示将fatab文件中的以#开头且后面是空白字符的行替换为空,同时
#删除以‘UUID’开头的行

-f SED_SCRIPTFILE:每行一个编辑命令;不必加引号

-r,--regexp-extended:支持使用扩展正则表达式

-i :直接编辑原文件;

  地址定界:   

(1)无地址指明:对全文进行逐行处理;

(2)单地址:

num:处理指定行数的行;

/pattern/:被此模式匹配到的每一行;

$:最后一行

(3)地址范围

m,n:从第m行到n行,包括m行和n行以及它们之间的所有行。

m,+n:表示从第m行开始,向后n行,包括m行。

m,/pattern/:表示从第m行开始,到被模式(pattern)第一次匹配到的行。

/pattern1/,/pattern2/:表示从第一次被pattern1匹配到的行,到第一次被pattern2匹配到的行。

(4)步进:~

1~2:所有奇数行,从第一行开始步进2

2~2:所有偶数行

 编辑命令:

      d:删除



       p:显示模式空间的内容

 注意:默认模式+编辑模式,故匹配行会显示两遍,加  -n 即可

 a \text:在匹配到的行后追加文本“text”,支持使用\n多行追加

 i \text:在匹配到的行前插入文本“text”,支持使用\n多行插入

 c \text:把匹配到的整行替换为此处指定的文本“text”

 w /PATH/TO/SOMEFILE:保存模式空间中匹配到的行至指定文件中;

 r /PATH/FROM/SOMEFILE:读取指定文件中的内容至当前被匹配到的行后面;即文件合并;

:为模式空间匹配到的行打印行号

:条件取反;

添加位置:地址定界!编辑命令



示例:



# 测试文件内容
 ~]# cat test 
The first line
The second line
The third line
The fourth line
The fifth line
The sixth line
# 删除
~]# sed '1,3d' test
The fourth line
The fifth line
The sixth line
# 显示
~]# sed '1~2p' test
The first line
The first line
The second line
The third line
The third line
The fourth line
The fifth line
The fifth line
The sixth line
~]# sed -n '1~2p' test  ---->显示奇数行
The first line
The third line
The fifth line
# 添加(a,i,b只举一例,用法相同)
]# sed '3a \this is a new line' test
The first line
The second line
The third line
this is a new line   ----->此处为新加行
The fourth line
The fifth line
The sixth line
# 将处理的行写入文件中
 ~]# sed '1~2w testout' test
The first line
The second line
The third line
The fourth line
The fifth line
The sixth line
~]# cat testout 
The first line
The third line
The fifth line
# 将文件中的行读入追加在指定位置
~]# sed '$r testout' test
The first line
The second line
The third line
The fourth line
The fifth line
The sixth line
The first line
The third line
The fifth line
# 给处理的文本标上行号
~]# sed '/line$/=' test
1
The first line
2
The second line
3
The third line
4
The fourth line
5
The fifth line
6
The sixth line
# 取反操作
~]# sed '/^$/!d'   ------> 不删除空白行




 s/pattern/text/修饰符:查找替换,其分隔符可自行指定,常用的有@,#等;即s@@@、

    s###亦可;

替换修饰符:

g:全局替换;无此选项时,sed仅会替换每一行的第一个被模式匹配到的内容;

w /PATH/TO/SOMEFILE:将替换成功的结果保存至指定的文件中

p:显示替换成功的行。

i: 查找时忽略大小写。

示例:

# 删除指定文件以空白字符开头行首的所有空白字符
~]# sed 's/^[[:space:]]\+//g' /etc/grub2.cfg
# 删除指定文件以#开头后面跟空白字符的行的前面的#号和所有空白字符
~]# sed 's/^#[[:space:]]*//g' /etc/fstab
# 取出一个路径的路径名
~]# echo "/etc/yum.repo.d/Base.repo" | sed -r 's#[^/]+/?$##g'



# 取出一个路径的文件名 ~]# echo "/etc/yum.repo.d/Base.repo" | sed -r 's#^/.*/([^/]+/?)$#\1#g'




高级编辑命令: 

h:把模式空间中的内容覆盖至保存空间中;

H:把模式空间中的内容追加到保持空间中;

g:把保持空间中的内容覆盖至模式空间中;

G:把保持空间中的内容追加至模式空间中;

x:把模式空间中的内容与保持空间中的内容互换;

n:读取匹配到的行的下一行至模式空间中;会覆盖原行

N:追加读取匹配到的行的下一行至模式空间中。

d:删除模式空间中的行

D:删除多行模式空间中的所有行;


一个极为复杂的示例:

# 逆序显示文件内容
~]# sed '1!G;h;$!D' /etc/fstab

 

    总结:sed的灵活使用可以给我们在文本处理上带来极大的便利,特别是在脚本中的灵活使用但是高级编辑命令用到了保持空间来完成操作,比较复杂。且日常用到不多,了解即可。


注:本文示例均在CentOS 6.7上进行测试。附件中包含了常用的一些正则表达式以及正则表达式30分钟脚程。


转载于:https://blog.51cto.com/flyalways/1730774