在这一章中开始讲述sed命令的基础用法。

一、阐述

  我们此前也讲过,Linux上的文本处理上的三剑客,分别是:

   文本处理三剑客:
       grep, egrep, fgrep:文本过滤器;
       sed:Stream Editor, 流编辑器,行;类似于vim一样的数据流编辑器,但是它是行编辑器。
       awk:文本格式化工具,报告生成器;

二、sed模式及命令用法

2.1 sed工作模式及原理

  刚才我们也提到过,sed是一个行编辑器,也就意味着sed只能处于一行文本,但sed与其它的文本处理的编辑工具一样,默认都不直接去编辑源文件,而是将其原来的数据复制一份,在内存中执行编辑操作,假如说有一个文本文件,实际上同时能够处理多个文件,我们以其中一个为例,我们知道的是每个文本文件通常是由多行数据组成,sed在该文件中一次读取出一行,并且放置到sed自己的工作车间内,并不会动源文件中的内容,只是将源文件其中的一行复制出来放置在自己专用的工作车间内进行加工,这个工作车间我们称之为pattern space,我们称之为模式空间,那么读取到一行之后,进行处理,其处理结果将会送到标准输出stdout

  默认情况下,sed可以针对该文件上每一行文本都能做出处理操作,但是我们也可以让sed仅处理文本文件中所符合条件的行,所谓符合条件的行就是由正则表达式所匹配,也称之为文本过滤,那么这样就变成了另一种重新描述的一种方式。sed每一次在文本中读出一行文本,读出来之后放置在pattern space的内存空间当中,放置在该内存空间中以后,sed不会执行其编辑操作,而是首先判断是否让sed所关注及匹配到的行,所谓sed关注到的行就是sed所给定的过滤模式,来看一下是否符合sed所给定的模式所匹配,如果是,则能够被匹配到,而后执行其编辑操作。称之为edit,将编辑到的结果可以输出至标准输出。如果说sed读取出来的行不能被sed所指定的pattern space能够匹配的话,那么既然是匹配(pattern),就会有两种结果:第一,能够被指定的pattern所匹配;第二,不能够被指定的pattern所匹配,如果无法匹配成功时,则不进行任何编辑操作,而是直接默认输出stdout。

  那么如果获取的数据可以被sed指定的行由pattern所匹配到,那么就能够进行编辑操作,那么如何编辑,怎么编辑,比如删除、查找并替换字符串等操作,总之要进行编辑,而后将其编辑的结果输出在stdout,当然,可以不用输出,因为有些结果可能没有办法进行输出,这个是需要注意的地方,所以输出对于编辑结构而言并不是默认结构,因为有些编辑叫做删除,那么在大体上能够匹配的话,则可以进行编辑,其编辑的结果可以指明输出至屏幕,如果不指定可能不会输出的,但是如果不匹配的话,那么其默认行为就是标准输出。

  但是我们可以明确指明,如果说不能被模式匹配到的行,不用输出也可以,它只是可以默认输出。所以说,sed大体上对于文本文件的编辑就刚才像我们所描述那些场景,每一次sed要逐行将文本文件中的内容读取到pattern space中来,而后去判断是否由模式操作进行匹配,能够被匹配到于是就采取编辑操作,如果不能够匹配,则默认不能够被模式空间中所匹配到的行的内容将其输出到屏幕中来,但我们可以隐藏这种输出,可以表示不让其输出,依次类推,逐行进行匹配,那么这就是sed大致的工作模式。

  但事实上sed还是实现其强大的功能,这个强大的功能在于sed其内存内部中不仅仅有模式空间,还有另一个内存空间,称之为保持空间hold space,这也意味着,编辑完之后,放入pattern space,如果模式匹配到则进行编辑,而编辑完成之后放入保持空间中去,所以可以玩一些魔数了,比如说让保持空间和模式空间中的数据交换,但对于用户来讲帮助不大,我们只需了解即可。所以我们掌握最为常见及普遍的功能。

2.2 sed命令

  sed命令的使用格式也非常简洁,sed后面可以添加一些选项,后面可以跟上一些脚本,而输入文件有多个。意味着sed一次可以处理多行文本。

   sed [OPTION]... 'script' [input-file]...

  而script的组成格式的关键由两个部分组成,第一个是地址定界,意思是从第几行到第几行,或者说是由第一个模式匹配到的行开始,到第一个被第二个模式所匹配到的行结束等,意思就是被行圈定之后,一旦被地址定界所匹配到之后,之后做出编辑,那么第二个是编辑命令,而这两个是要一起来进行使用的,这就是地址定界+编辑命令来指出文本来做出其处理操作。

    script:
        地址定界编辑命令

  那么除了script之外,还有一些常用的option,而后再讲它的地址定界机制和各种编辑命令。

    常用选项:
        -n:不输出模式空间中的内容至屏幕;
        -e script, --expression=script:可以指定一个sed命令中指定编辑多个脚本或多个编辑命令,也称为多点编辑;
        -f /PATH/TO/SED_SCRIPT_FILE:指明sed脚本编辑命令文件路径;
            每行一个编辑命令:
        -r, --regexp-extended:支持使用扩展正则表达式;
        -i[SUFFIX], --in-place[=SUFFIX]:直接编辑源文件;

  将文本文件中的一行被读到pattern space之后,该模式空间无论是否能够被编辑命令所匹配,通常而言都会将其输出到屏幕中去,但是匹配之后还有第二种操作,就是edit,匹配到默认也是可以输出至stdout,但是也可被二种行为edit进行编辑,编辑完成之后如何处理取决于用户所输入的编辑命令,一旦一行文本被读到模式空间以后,它首先将模式空间中的内容输出到屏幕上来,其次在判断是否为模式空间中的模式所匹配到,如果匹配到则可以进行编辑,那么如果不期望将模式空间中的内容输出至屏幕中来的话,使用-n选项来禁用该功能。

2.3 地址定界

  地址定界就是专门用来说script当中如何指明对于那些行进行编辑,那么这里的地址定界方式与我们之前讲过的vim中的地址定界功能是相似的。

    地址定界:
        (1) 空地址;对全文进行处理;
        
        (2) 单地址;
            #:指定行;
            /PATTERN/:被此模式所匹配到的每一行;
            
        (3) 地址范围
            #,#
            #,+#:从当前行开始,向下总共#行;
            #,/pat1/
            /pat1/,/pat2/
            
        (4) 步进:~
            1~2:所有奇数行;
            2~2:所有偶数行;

2.4 编辑命令

  接下来我们讲述一下sed常用的编辑命令。

   d:删除(删除模式空间中的内容);建议不要于-n使用
   p:显示模式空间中的内容;
   a \text:在行后追加文本"text",支持使用\n实现多行追加;
   i \text:在行前插入文本"text",支持使用\n实现多行追加;
   c \text:把匹配到的行替换为此处指定的文本"text";
   w /PATH/TO/SOMEFILE:保存模式空间匹配到的行至指定文本中;
   r /PATH/FROM/SOMEFILE:读取指定文件的内容至当前文件被模式匹配到的行处后面;文件合并;
   =:为模式匹配到的行打印行号;
   !:条件取反;
      地址定界!编辑命令;
   s///:查找替换,其分隔符号可自行指定,常用的有:s@@@, s###等;
      替换标记:
         g:全局替换;
         w /PATH/TO/SOMEFILE:将替换成功的结果保存至指定文件中;
         p:显示替换成功的行;

  示例1:将/etc/fstab文件中的1-5行进行删除。

# sed '1,5d' /etc/fstab

  示例2:将奇数行显示两遍。在模式空间中默认编辑为输出。

# sed '1~2p' /etc/fstab

  示例3:显示奇数行,或显示偶数行。

# sed -n '1~2p' /etc/fstab
# sed '1~2d' /etc/fstab

  示例4:/etc/fstab第三行的前面插入一个"# Are You Ok?"的信息;然后在该行后面插入该信息。

# sed '3i \# Are You Ok?' /etc/fstab
# sed '3a \# Are You Ok?' /etc/fstab

  那么我们刚才也讲到过,它也支持多行文本插出,例如:

  示例5:在第三行的后面,在添加"# Are You Ok?"的同时,追加一行为"# Hello Thank You!"的信息。

# sed '3a \# Are You Ok?\n# Hello Thank You!' /etc/fstab

  除了指定行号,还可以指定其正则表达式的模式匹配。所以当有必要有些符合条件的内容加上同样的注释信息时,可以实现用类似的方式来实现。

  示例6:匹配以UUID开头的行,在该行的后面加上"# Thank You?"信息,而后追加一行为"# Are You Ok?"的信息。

# sed '/^UUID/a \# Think You!\n# Are You Ok?' /etc/fstab

  示例7:将UUID开头的行替换为"# Are You Ok?"的信息。

# sed '/^UUID/c \# Are You Ok?' /etc/fstab

  示例8:我们以UUID开头的行另存为/tmp/目录下,取名为fstab.new。

# sed -n '/^UUID/w /tmp/fstab' /etc/fstab.new

  示例9:在/etc/fstab文件下的第三行后插入/etc/issue文件中的内容。

# sed '3r /etc/issue' /etc/fstab

  示例10:取出非#号开头的行。需要注意的是,要放置在条件的后面与命令之前。

# sed '/^#/!d' /etc/fstab

  示例11:将/etc/fstab文件中的#及空白字符全部删除,同时也要删除UUID开头的行。

# sed -e 's@^#[[:space:]]*@@g' -e '/^UUID/d' /etc/fstab

三、高级编辑命令

  在这个高级编辑命令当中,虽然并不需要掌握,但是最起码要了解一下。

   h:将模式空间中的内容覆盖至保持空间中;
   H:将模式空间中的内容追加至保持空间中;
   g:将保持空间中的内容覆盖至模式空间中;
   G:将保持空间中的内容追加至模式空间中;
   x:把模式空间中的内容于保持空间中的内容互换;
   n:覆盖读取匹配到的行的下一行至模式空间中;
   N:追加读取匹配到的行的下一行至模式空间中;
   d:删除模式空间中的行;
   D:删除多行模式中间中的所有行;