• linux shell sed命令


    什么是sed

      sed 是 stream editor 的缩写,中文称之为“流编辑器”。

      sed 命令是一个面向行处理的工具,它以“行”为处理单位,针对每一行进行处理,处理后的结果会输出到标准输出(STDOUT)。你会发现 sed 命令是很懂礼貌的一个命令,它不会对读取的文件做任何贸然的修改,而是将内容都输出到标准输出中。

      sed 命令是面向“行”进行处理的,每一次处理一行内容。处理时,sed 会把要处理的行存储在缓冲区中,接着用 sed 命令处理缓冲区中的内容,处理完成后,把缓冲区的内容送往屏幕。接着处理下一行,这样不断重复,直到文件末尾。这个缓冲区被称为“模式空间”(pattern space)。

    • sed命令处理的内容是模式空间中的内容,而非直接处理文件内容。如果加上参数 i 则可直接修改文件内容
    • 示例:sed -i 's/原字符串/新字符串/' /home/test.txt

    sed语法

    sed [-nefr参数] [function] [filePath]  

      用到 sed,别忘了用单引号将[function] 部分用单引号括起来。

    选项与参数

    描述

    -n

    使用 silent 模式。在一般 sed 的用法中,输入的数据都会被输出到屏幕上。但如果加上 -n 参数后,则不会显示,如果有跟着 p 标志,被 sed 特殊处理的那一行会被列出来

    -e

    直接在命令行界面上进行 sed 的动作编辑,执行多条子命令

    -f

    将 sed 的动作写在一个文件内, -f filename 执行脚本文件的 sed 动作

    -r

    sed 的动作支持的是延伸型正则表达式的语法

    -i

    直接修改读取的文件内容

    • 选项-n,加上-n选项后被设定为安静模式,也就是不会输出默认打印信息,除非子命令中特别指定打印 p 选项,则只会把匹配修改的行进行打印
    • 选项-e,多条子命令连续进行操作
    • 选项-i,直接修改读取的文件内容
    • 选项-f,执行文件脚本

      

    ---- 两行都打印出来 ----
    server11:~/test # echo -e 'hello \nworld' | sed 's/hello/csc/'
    csc 
    world
    ---- 一行也没打印 -----
    server11:~/test # echo -e 'hello \n world' | sed -n 's/hello/csc/'
    ---- 打印了匹配行 -----
    server11:~/test # echo -e 'hello \n world' | sed -n 's/hello/csc/p'
    csc 
    
    # echo -e 'hello world' | sed -e 's/hello/csc/' -e 's/world/lwl/'
    csc lwl
    #
    
    
    ---- 加上参数 i 可以直接修改文件内容----
    # cat file.txt
    lwl word
    # sed -i 's/lwl/hello/' file.txt
    # cat file.txt
    hello word
    #
    
    sed.script脚本内容:
    s/hello/csc/
    s/world/lwl/
    ------
    echo "hello world" | sed -f sed.script
    结果:csc lwl
    

    function表达式:[n1[,n2]] function or /{pattern}/function

    • n1, n2 :可选项,一般代表“选择进行function处理的行数”,举例来说,如果「function」是需要在 10 到 20 行之间进行的,则表示为 10,20 [function]
    • 如果需用正则表达式匹配字符串,则可用 /{pattern}/ 匹配

    格式:

      显示 test 文件的第 10 行到第 20 行的内容:

    $ sed -n '10,20p' test
    

      

    test.txt 内容 
    111
    222
    333
    444
    ----- 删除非第2第3行之间的所有行 ----------
    server11:~ # sed -i '2,3!d' test.txt 
    server11:~ # cat test.txt
    222
    333
    ------ 正则表达式匹配 ------------
    server11:~ # echo 'clswcl.txt' | sed -nr '/.*/p'
    clswcl.txt  //  /{pattern}/ = /.*/
    

      function 有以下这些选项

    function

    描述

    a

    新增:a 的后面可以接字串,而这些字串会在新的一行出现(目前的下一行)

    i

    插入:i 的后面可以接字串,而这些字串会在新的一行出现(目前的上一行)

    c

    取代:c 的后面可以接字串,这些字串可以取代 n1,n2 之间的行

    d

    删除:因为是删除啊,所以 d 后面通常不接任何东西

    p

    打印:亦即将某个选择的数据印出。通常 p 会与参数 sed -n 一起运行

    s

    取代:可以直接进行取代的工作哩!通常这个 s 的动作可以搭配正则表达式!例如:1,20 s/old/new/g

    • function:-a,行后插入新行
    • function:-i,行前插入新行
    • function:-c,修改指定内容行
    • function:-d,删除特定字符串
    sed -i '/特定字符串/a 新行字符串' fileName
    
    sed -i '/特定字符串/i 新行字符串' fileName
    
    sed -i '/特定字符串/c csc lwl' fileName 
    
    sed -i '/特定字符串/d' fileName 
    

    sed s子命令: s/{pattern}/{replacement}/{flags}

    • {pattern}是正则表达式
    • 如果{pattern}存在分组,{replacement}中的"\n"代表第n个分组,"&"代表整个匹配的字符串。详情看示例
    • flags的参数如下

    flags

    描述

    n

    可以是1-512,表示第n次出现的情况进行替换

    g

    全局更改

    p

    打印模式空间的内容

    w file

    写入到一个文件file中

    sed -i 's/原字符串/新字符串/' /home/test.txt
    

      

    元字符集编辑
    ^锚定行的开始如:/^sed/匹配所有以sed开头的行。
    $锚定行的结束 如:/sed$/匹配所有以sed结尾的行。
    .匹配一个非换行符的字符 如:/s.d/匹配s后接一个任意字符,然后是d。
    *匹配零或多个字符 如:/*sed/匹配所有模板是一个或多个空格后紧跟sed的行。
    []匹配一个指定范围内的字符,如/[Ss]ed/匹配sed和Sed。
    [^]匹配一个不在指定范围内的字符,如:/[^A-RT-Z]ed/匹配不包含A-R和T-Z的一个字母开头,紧跟ed的行。
    \(..\)保存匹配的字符,如s/\(love\)able/\1rs,loveable被替换成lovers。
    &;保存搜索字符用来替换其他字符,如s/love/**&**/,love这成**love**。
    \<;锚定单词的开始,如:/\<love/匹配包含以love开头的单词的行。
    \>;锚定单词的结束,如/love\>/匹配包含以love结尾的单词的行。
    x\{m\}重复字符x,m次,如:/0\{5\}/匹配包含5个o的行。
    x\{m,\}重复字符x,至少m次,如:/o\{5,\}/匹配至少有5个o的行。
    x\{m,n\}重复字符x,至少m次,不多于n次,如:/o\{5,10\}/匹配5--10个o的行。
    

      

    实例

    删除:d命令
    $ sed '2d' example-----删除example文件的第二行。
    $ sed '2,$d' example-----删除example文件的第二行到末尾所有行。
    $ sed '$d' example-----删除example文件的最后一行。
    $ sed '/test/'d example-----删除example文件所有包含test的行。
    替换:s命令 $ sed 's/test/mytest/g' example-----在整行范围内把test替换为mytest。如果没有g标记,则只有每行第一个匹配的test被替换成mytest。 $ sed -n 's/^test/mytest/p' example-----(-n)选项和p标志一起使用表示只打印那些发生替换的行。也就是说,如果某一行开头的test被替换成mytest,就打印它。 $ sed 's/^192.168.0.1/&localhost/' example-----&;符号表示替换换字符串中被找到的部份。所有以192.168.0.1开头的行都会被替换成它自已加localhost,变成192.168.0.1localhost。 $ sed -n 's/\(love\)able/\1rs/p' example-----love被标记为1,所有loveable会被替换成lovers,而且替换的行会被打印出来。 $ sed 's#10#100#g' example-----不论什么字符,紧跟着s命令的都被认为是新的分隔符,所以,“#”在这里是分隔符,代替了默认的“/”分隔符。表示把所有10替换成100。
    选定行的范围:逗号 $ sed -n '/test/,/check/p' example-----所有在模板test和check所确定的范围内的行都被打印。 $ sed -n '5,/^test/p' example-----打印从第五行开始到第一个包含以test开始的行之间的所有行。 $ sed '/test/,/check/s/$/sed test/' example-----对于模板test和check之间的行,每行的末尾用字符串sed test替换。
    多点编辑:e命令 $ sed -e '1,5d' -e 's/test/check/' example
        //-----(-e)选项允许在同一行里执行多条命令。如例子所示,第一条命令删除1至5行,第二条命令用check替换test。
        //命令的执行顺序对结果有影响。如果两个命令都是替换命令,那么第一个替换命令将影响第二个替换命令的结果。
    $ sed --expression='s/test/check/' --expression='/love/d' example
        //-----一个比-e更好的命令是--expression。它能给sed表达式赋值。
    
    从文件读入:r命令
    $ sed '/test/r file' example-----file里的内容被读进来,显示在与test匹配的行后面,如果匹配多行,则file的内容将显示在所有匹配行的下面。
    写入文件:w命令 $ sed -n '/test/w file' example-----在example中所有包含test的行都被写入file里。
    追加命令:a命令 $ sed '/^test/a\\--->this is a example' example<-----'this is a example'被追加到以test开头的行后面,sed要求命令a后面有一个反斜杠。
    插入:i命令 $ sed '/test/i\\new line-------------------------' example如果test被匹配,则把反斜杠后面的文本插入到匹配行的前面。
    下一个:n命令 $ sed '/test/{ n; s/aa/bb/; }' example-----如果test被匹配,则移动到匹配行的下一行,替换这一行的aa,变为bb,并打印该行,然后继续。
    变形:y命令 $ sed '1,10y/abcde/ABCDE/' example-----把1--10行内所有abcde转变为大写,注意,正则表达式元字符不能使用这个命令。
    退出:q命令 $ sed '10q' example-----打印完第10行后,退出sed。
    保持和获取:h命令和G命令 $ sed -e '/test/h' -e '/$/G' example-----在sed处理文件的时候,每一行都被保存在一个叫模式空间的临时缓冲区中,除非行被删除或者输出被取消,否则所有被处理的行都将打印在屏幕上。接着模式空间被清空,并存入新的一行等待处理。在这个例子里,匹配test的行被找到后,将存入模式空间,h命令将其复制并存入一个称为保持缓存区的特殊缓冲区内。第二条语句的意思是,当到达最后一行后,G命令取出保持缓冲区的行,然后把它放回模式空间中,且追加到现 在已经存在于模式空间中的行的末尾。在这个例子中就是追加到最后一行。简单来说,任何包含test的行都被复制并追加到该文件的末尾。
    保持和互换:h命令和x命令 $ sed -e '/test/h' -e '/check/x' example -----互换模式空间和保持缓冲区的内容。也就是把包含test与check的行互换。

      

    sed 命令的简单例子

    现看原文件
    # cat test.txt
    test01
    test02
    test03
    
    用sed命令,来删除文件中带符号“2”的行
    # sed '/2/d' test.txt
    test01
    test03
    
    sed操作是在自己的模式空间中执行的,所以是不会改动test.txt原原文件
    # cat test.txt
    test01
    test02
    test03
    #
    

      这个命令的 command 部分是/2/d,而且它是用单引号括起来的。

      用到 sed,别忘了用单引号将 command 部分括起来。

      /2/d中的 d 表示删除,意思是说,只要某行内容中含有字符 2,就删掉这一行。(sed 所谓的删除都是在模式空间中执行的,不会真正改动 roc.txt 原文件。)

    显示 test 文件的第 10 行到第 20 行的内容:

    $ sed -n '10,20p' test
    

    将所有以 d 或 D 开头的行里的所有小写 x 字符变为大写 X 字符:

    $ sed '/^[dD]/s/x/X/g' test
    

    要删除每行最后的两个字符:

    #点号表示一个单个字符, 两个点号就表示两个单个字符
    [roc@roclinux ~]$ sed 's/..$//' test
    

      用 sed‘/..$/d’test 为什么不行呢,d 不是表示删除么?用 d 是不行的,这是因为 d 表示删除整行内容,而非字符。'/..$/d'表示的是匹配所有末尾含有两个字符的行,然后删除这一整行内容。

    删除每一行的前两个字符:

    $ sed 's/..//' test

    用 sed 的S命令,实现cut效果

    假如我们想实现类似于 cut-d:-f 1/etc/passwd 的效果,也就是以冒号为间隔符提取第 1 个域,用 sed 命令应该怎么操作呢?

    # cat /etc/passwd
    root:x:0:0:root:/root:/bin/bash
    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
    lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
    sync:x:5:0:sync:/sbin:/bin/sync
    # head -n 5 /etc/passwd | sed 's/:.*$//'
    root
    bin
    daemon
    adm
    lp
    

      command 部分指定成了's/:.*$//',表示我们要把每一行的第一个冒号到结尾的部分都清空,这样留下的便是第一个冒号前的内容啦。

     这里 command用到的是s命令s命令的语法格式如下:

    s/regexp/replacement/[flags]
    regexp是要查找匹配的正则 replacement是替换内容 [flags]是可选的,用来添加一些额外标记参数
     

    & 符号的妙用

    $ cat mysed.txt
    Beijing
    London
     
    $ sed 's/B.*/&2008/' mysed.txt
    Beijing2008
    London
    $ sed 's/Bei/&2008/' mysed.txt
    Bei2008jing
    London

      这个命令的作用是将包含 ‘B.*’ 的字符串后面加上 2008 四个字符。这个命令中我们用到了 & 字符,在 sed 命令中,它表示的是“之前被匹配的部分”,在我们的例子中就是 Beijing 

    sed 中的括号

    在 sed 命令中,其实小括号‘()’也是有深意的:

    $ echo "hello world" | sed 's/\(hello\).*/world \1/'
    world hello
    

      原本是“hello world”,经过 sed 的处理,输出变成了“world hello”。

      这个例子中就用到了小括号,我们称之为“sed 的预存储技术”,也就是命令中被“(”和“)”括起来的内容会被依次暂存起来,存储到 \1、\2…里面。这样你就可以使用‘\N’形式来调用这些预存储的内容了。

      只在每行的第一个和最后一个 Beijing 后面加上 2008 字符串,言下之意就是,除了每行的第一个和最后一个 2008 之外,这一行中间出现的 Beijing 后面就不要加 2008 啦。这个需求,真的是很复杂很个性化,但 sed 命令仍然可以很好地满足:

    $ cat mysed.txt
    Beijing Beijing Beijing Beijing
    London London London London
     
    $ sed 's/\(Beijing\)\(.*\)\(Beijing\)/\12008\2\32008/' mysed.txt
    Beijing2008 Beijing Beijing Beijing2008
    London London London London
    

      我们再次使用了预存储技术,存储了三项内容,分别代表第一个 Beijing、中间的内容、最后的 Beijing。而针对\1\3,我们在其后面追加了 2008 这个字符串。

    更聪明的定位行范围

    $ cat mysed.txt
    Beijing 2003
    Beijing 2004
    Beijing 2005
    Beijing 2006
    Beijing 2007
    Beijing 2008
    Beijing 2007
     
    #展示匹配了2005的行和2007的行之间的内容
    $ sed -n ‘/2005/,/2007/p’ mysed.txt
    Beijing 2005
    Beijing 2006
    Beijing 2007
    

      使用 /2005/ 来匹配行范围的首行,用 /2008/ 来匹配行范围的尾行。可以看到,在匹配尾行时,只要遇到第一个符合要求的行,就会停止,而不会再继续向后匹配了。所以,sed 命令只是匹配到了第一个 2007,并没有匹配到第二个 2007。

    用 -e 选项来设置多个 command

    sed格式:
    sed command file

       sed 命令可以包含不只一个 command。如果要包含多个 command,只需在每个 command 前面分别加上一个-e选项即可。

    #通过2个-e选项设置了两个command
    [roc@roclinux ~]$ sed -n -e ‘1,2p’ -e ‘4p’ mysed.txt
    Beijing 2003
    Beijing 2004
    Beijing 2006
    

      有一个地方值得大家注意,那就是-e选项的后面要立即接 command 内容,不允许再夹杂其他选项。

      -e选项支持设置多个 command,这原本是一件好事情,让我们可以更方便地实现一些替换效果。但是,这也给我们带来了幸福的烦恼,假如我们设定了很多个 command,那它们的执行顺序是怎样的呢?   //是按前后顺序执行的;
      如果这一点不搞明白,-e选项带来的或许只有混乱而非便捷。我们来一起看看下面的例子:

    #先看看文件的内容
    [roc@roclinux ~]$ cat mysed.txt
    Beijing 2003
    Beijing 2004
    Beijing 2005
    Beijing 2006
    Beijing 2007
    Beijing 2008
     
    #我们设置了两个command
    [roc@roclinux ~]$ sed -e ‘s/Beijing/London/g’ -e ‘/Beijing/d’ mysed.txt
    London 2003
    London 2004
    London 2005
    London 2006
    London 2007
    London 2008
    

      前一个 command 表示将 Beijing 替换为 London,而后一个 command 表示要删除包含了 Beijing 字符串的行,但是最后的结果却是输出了所有行,并没有发现被删除的行。这是因为第一个 command 已经将 Beijing 都替换成了 London,所以怪第二个 command 找不到 Beijing 了。

    用 -f 选项设定 command 文件

    如果你的 sed 命令的 command 部分很长,那么可以将内容写到一个单独的文件中,然后使用-f选项来指定这个文件作为我们 sed 命令的 command 部分:

    #这是我们事先写好的文件
    [roc@roclinux ~]$ cat callsed
    /2004/,/2006/p
     
    #我们用-f选项来指定command文件
    [roc@roclinux ~]$ sed -n -f callsed mysed.txt
    Beijing 2004
    Beijing 2005
    Beijing 2006
    

      -f选项并不难,而且我会经常使用,因为一些比较常用的匹配规则,我都会存到单独的文件中,不用再费脑子记忆啦。

    内容插入

    sed 命令远比你想象的要强大,它不仅可以处理本行内容,还可以在这一行的后面插入内容:

    #我们将要插入的内容保存到一个单独的文件中
    [roc@roclinux ~]$ cat ins.txt
    ====China====
     
    #展示一下我们要处理的文件
    [roc@roclinux ~]$ cat mysed.txt
    Beijing 2003
    Beijing 2004
    Beijing 2005
    Beijing 2006
    Beijing 2007
    Beijing 2008
     
    #看, 我们使用r来实现插入
    [roc@roclinux ~]$ sed ‘/2005/r ins.txt’ mysed.txt
    Beijing 2003
    Beijing 2004
    Beijing 2005
    ====China====
    Beijing 2006
    Beijing 2007
    Beijing 2008
    

      通过效果可以看出来,我们在文件中的含有 2005 字符串的行的下面一行插入了 ins.txt 文件的内容。

      除了可以通过指定文件来插入外,其实还可以使用 a\ 在特定行的“下面”插入特定内容:

      只要使用a\然后加上要插入的内容就可以轻松实现啦。

    #文件内容
    [roc@roclinux ~]$ cat new.txt
    Beijing 2004
    Beijing 2005
    Beijing 2006
     
    #我们希望在2004的下一行插入China
    [roc@roclinux ~]$ sed ‘/2004/a\China’ mysed.txt
    Beijing 2003
    Beijing 2004
    China
    Beijing 2005
    Beijing 2006
    Beijing 2007
    Beijing 2008
    

      

    既然可以在一行的下面插入内容,那是否可以在一行的上面插入内容呢?答案是当然可以,那就是使用i\动作:

    $ sed ‘/2004/i\China’ mysed.txt
    Beijing 2003
    China
    Beijing 2004
    Beijing 2005
    Beijing 2006
    Beijing 2007
    Beijing 2008 
    

      

     子命令--y 命令使用

    将所有的 e 和 i 互换。

    #原文件内容
    [roc@roclinux ~]$ cat mysed.txt
    Beijing 2003
    Beijing 2004
    Beijing 2005
    Beijing 2006
    Beijing 2007
    Beijing 2008
     
    #y就是按照字符顺序, 实现前后的替换
    [roc@roclinux 20160229]$ sed 'y/ei/ie/' mysed.txt
    Biejeng 2003
    Biejeng 2004
    Biejeng 2005
    Biejeng 2006
    Biejeng 2007
    Biejeng 2008
    

      y///s///有什么区别呢?主要有以下两点:

    • y 的语法格式是 y/source/dest/,表示将 source 中的字符对位替换为 dest 中的字符。而 s 的语法格式是 s/regexp/replacement/,表示通过正则匹配到的内容替换为 replacement 部分
    • y 只是简单的逐字替换,没有很多花样。s 支持 & 符号和预存储等特性,可以实现更多灵活的替换效果。

    这时,一些 GEEK 或许会想到一种情况,那就是 y/ee/ei/ 会产生什么效果呢?因为这里面出现了两个同样的字符,我们还是通过例子来看一下:

    [roc@roclinux 20160229]$ sed 'y/ee/ie/' mysed.txt
    Biijing 2003
    Biijing 2004
    Biijing 2005
    Biijing 2006
    Biijing 2007
    Biijing 2008
    

     

    如果 source 部分出现了重复的字符,则只有第一次出现的对位替换会产生效果,后面的并不会起作用。或许下面这个例子更加清晰些: 

    #原文件内容
    [roc@roclinux ~]$ cat mysed.txt
    Beijing 2003
    Beijing 2004
    Beijing 2005
    Beijing 2006
    Beijing 2007
    Beijing 2008
     
    #iji到iba的替换中, 这里的i重复了,所以只有j到b起到了效果
    [roc@roclinux 20160229]$ sed 'y/iji/iba/' mysed.txt
    Beibing 2003
    Beibing 2004
    Beibing 2005
    Beibing 2006
    Beibing 2007
    Beibing 2008
    

      

     子命令--n 命令,通过n来控制行的下移

    实现隔行处理的效果,比如只需对偶数行做某个替换,这时候,我们就需要 n 动作的帮忙:

    #原文件内容
    [roc@roclinux ~]$ cat mysed.txt
    Beijing 2003
    Beijing 2004
    Beijing 2005
    Beijing 2006
    Beijing 2007
    Beijing 2008
     
    #我们同时使用了n动作和y动作
    [roc@roclinux ~]$ sed ‘/200/{n;y/eijng/EIJNG/;}’ mysed.txt
    Beijing 2003
    BEIJING 2004
    Beijing 2005
    BEIJING 2006
    Beijing 2007
    BEIJING 2008
    

      大写的 BEIJING 是隔行出现的。这就是n选项在起作用,它的真实作用是将下一行内容放到处理缓存中,这样,就让当前这一行躲避开了替换动作。

     子命令--w命令,将指定行写入到特定文件中

     w 动作,它可以将匹配到的内容写入到另一个文件中,即用来实现内容的筛选与保存:

    #将包含2004、2005、2006的行保存到new.txt文件中
    [roc@roclinux ~]$ sed ‘/200[4-6]/w new.txt’ mysed.txt
    Beijing 2003
    Beijing 2004
    Beijing 2005
    Beijing 2006
    Beijing 2007
    Beijing 2008
     
    #我们要的内容已经乖乖到碗里来了
    [roc@roclinux ~]$ cat new.txt
    Beijing 2004
    Beijing 2005
    Beijing 2006
    

      

    部分摘自:http://c.biancheng.net/linux/sed.html

  • 相关阅读:
    剑指offer-树的子结构
    剑指offer-二叉搜索树的后序遍历序列
    剑指offer-调整数组顺序使奇数位于偶数前面
    剑指offer-包含min函数的栈
    剑指offer-从上往下打印二叉树
    剑指offer-链表中倒数第k个结点
    剑指offer-合并两个排列的链接
    剑指offer-替换空格
    剑指offer-旋转数组的最小数字
    剑指offer-数字在排序数组中出现的次数
  • 原文地址:https://www.cnblogs.com/lei2017/p/16292915.html
Copyright © 2020-2023  润新知