暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

你所不知道的那些sed命令

CoderMeng 2021-04-12
921


sed 全名 stream editor,一般用于文本内容替换。本文介绍日常工作中常用到的 sed 命令,更加完整的说明可以点击文末阅读原文参考 sed 手册。


01

模式空间(pattern space)


  • 将文件以为单位读取到内存(模式空间)

  • 使用 sed 的每个脚本对该行进行操作

  • 处理完成后输出该行


如下所示,读取 a.log 文件第一行内容,sed 中有 2 个替换脚本,第一个将 aa 替换成 @@ ,第二个将 bb 替换成 !! ,最后输出结果。

    meng➜/tmp» cat a.log     
    aa bb cc
    meng➜/tmp» sed 's/aa/@@/;s/bb/!!/' a.log   
    @@ !! cc


    02

    替换命令 s


    字符串替换,将文件中 src 字符串替换成 new,支持多个替换脚本


      sed ’s/src/new/‘ filename
      sed -e ’s/src/new/’ -e ’s/src1/new1/‘ filename
      # 这里等同于下面分号隔开
      sed 's/src/new/;s/src1/new1/' filename


      默认只会输出替换后的文本,-i 可以直接将源文件修改掉。


        sed -i 's/src/new/' filename


        正则替换:最常用的替换方式,需要你对正则表达式比较熟悉。


          sed ’s/正则表达式/new/‘ filename
          sed -r ’s/扩展正则表达式/new/ filenam


          # 示例:每行前面添加 #
          sed 's/^/#/' filename

          扩展正则表达式包括 ?, +, |, ( ) 这几个字符


          在扩展正则表达式中,使用圆括号匹配的内容可以当做变量来使用。比如我们可以将 aa 字符前加两个 !!


            meng➜/tmp» sed -r 's/(aa)/!!\1/' a.log  
            !!aa bb c


            03

            标志位


            s/src/new/标志位

            • g:每次出现都替换。

            • 数字:替换第几次出现,可以数字+g 替换第几次之后。

            • p:打印模式空间内容


            默认每行只会替换匹配的第一个,我们可以通过 g 来替换所有


              meng➜/tmp» cat b.log   
              aa aa aa aa
              meng➜/tmp» sed 's/aa/@@/g' b.log
              @@ @@ @@ @@
              meng➜/tmp» sed 's/aa/@@/2' b.log
              aa @@ aa aa
              meng➜/tmp» sed 's/aa/@@/2g' b.log
              aa @@ @@ @@


              p 将匹配的内容进行再次打印。加 p 后匹配的内容会被打印两次,第一次是标准输出,第二次是模式空间内容输出。这个可以结合 -n 使用,-n 表示处理完不进行标准输出。比如:在测试命令的时候,文件行数非常多,我只关心命令生效的内容。


                meng➜/tmp» cat c.log 
                aa aa aa aa
                bb bb
                meng➜/tmp» sed 's/aa/@@/p' c.log   
                @@ aa aa aa
                @@ aa aa aa
                bb bb
                meng➜/tmp» sed -n 's/aa/@@/p' c.log 
                @@ aa aa aa


                04

                寻址


                sed 默认对每行进行操作,增加寻址后仅对匹配的行进行操作。


                • /正则表达式/s/src/new/g。

                • 行号s/old/new/g。行号可以是具体的行,也可以是最后一行 $ 符合。

                • 可以使用两个寻址符号,也可以混合使用行号和正则。

                • /正则表达式/{ s/src/new;s/src/new/ },多个替换命令。


                  meng➜/tmp» cat d.log   
                  aa aa
                  11 aa
                  cc aa
                  meng➜/tmp» sed '/^[a-z]/s/aa/@@/' d.log
                  @@ aa
                  11 aa
                  cc @@
                  meng➜/tmp» sed '2s/aa/@@/' d.log
                  aa aa
                  11 @@
                  cc aa
                  meng➜/tmp» sed '2,3s/aa/@@/' d.log
                  aa aa
                  11 @@
                  cc @@
                  meng➜/tmp» sed '/^[a-z]/,$s/aa/@@/' d.log
                  @@ aa
                  11 @@
                  cc @@


                  /^[a-z]/,$s/ 从 /^[a-z]/ 匹配的行开始,一直到最后一行


                  05

                  其他

                  d 删除匹配的行

                    meng➜/tmp» sed '/11/d' d.log 
                    aa aa
                    cc aa

                    a 追加

                      # 在匹配的行后追加字符串 hello
                      meng➜/tmp» sed '/11/a hello' d.log
                      aa aa
                      11 aa
                      hello
                      cc aa

                      i 插入

                        meng➜/tmp» sed '/11/i hello' d.log 
                        aa aa
                        hello
                        11 aa
                        cc aa

                        c 更改

                          # 相当于直接替换掉这一行
                          meng➜/tmp» sed '/11/c hello' d.log
                          aa aa
                          hello
                          cc aa

                          p 打印

                            # 打印长度为 6 的回文串
                            meng➜/tmp» sed -rn '/(.)(.)(.)\3\2\1/p' word.log
                            redder


                            06

                            多行匹配


                            有了 N 、P 、D 我们就可以多行内容一起处理了。


                            • N 将下一行加入到模式空间。

                            • D 删除模式空间中的第一个字符到第一个换行符。

                            • P 打印模式空间中的第一个字符到第一个换行符。


                              meng➜/tmp» cat e.log  
                              hel
                              lo
                              # 将第二行合并到第一行,然后将换行符删掉
                              meng➜/tmp» sed 'N;s/\n//' e.log
                              hello


                              接下来看个示例,hello meng 被换行分隔成了多行,将它合并成一行,并替换成 hello sed。


                                meng➜/tmp» cat f.log  
                                hell
                                o meng hel
                                lo meng
                                # 处理流程见下图
                                meng➜/tmp» sed 'N;s/\n//;s/meng/sed\n/;P;D' f.log
                                hello sed
                                hello sed


                                07

                                保持空间(hold space)


                                保持空间也是一块暂存区域,我们可以将模式空间的内容复制到保持空间,也可以将保持空间内容复制到模式空间,方便我们对多行进行操作。


                                • h 和 H 将模式空间的内容存放到保持空间,小写是覆盖模式,大写是追加模式。

                                • g 和 G 将保持空间的内容取出到模式空间,大小写含义同上。

                                • x 交换模式空间和保持空间内容。


                                保持空间默认有一个初始字符:换行符


                                看个示例,tac 命令是将文件倒序输出,用 sed 怎么实现呢?


                                  ➜  tmp cat g.log
                                  1
                                  2
                                  3
                                  ➜ tmp sed -n '1h;1!G;$!x;$p' g.log
                                  3
                                  2
                                  1


                                  执行流程如下图


                                  • 1h:只对第一行执行 h

                                  • 1!G:对第一行不执行 G

                                  • $!x:对最后一行不执行 x



                                  倒序输出的命令我们还可以精简,如下:


                                    # 不加 1! 会多个换行,不知道为什么的同学,说明上文没认真看
                                    sed -n '1!G;h;$p' g.log
                                    sed '1!G;h;$!d' g.log


                                    换行符改成 , 号分隔


                                      ➜  tmp sed '1h;1!H;$x;$!d;s/\n/,/g' g.log
                                      1,2,3


                                      推荐阅读:


                                      Linux job control


                                      Google Protocol Buffers 序列化原理



                                      长按二维码关注,获得更多干货文章


                                      文章转载自CoderMeng,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

                                      评论