sed基本知识详解

来源:互联网 发布:人肉好吃吗 知乎 编辑:程序博客网 时间:2024/04/29 07:40

sed 匹配正则表达式  可以实现替代 查找  打印 等功能

模式空间  pattern  一行一行地进行替代  多命令下也是如此

sed的处理流程,简化后是这样的:

  1. 读入新的一行内容到缓存空间;
  2. 从指定的操作指令中取出第一条指令,判断是否匹配pattern;
  3. 如果不匹配,则忽略后续的编辑命令,回到第2步继续取出下一条指令;
  4. 如果匹配,则针对缓存的行执行后续的编辑命令;完成后,回到第2步继续取出下一条指令;
  5. 当所有指令都应用之后,输出缓存行的内容;回到第1步继续读入下一行内容;
  6. 当所有行都处理完之后,结束
  7. 举例:
  8. sed -e 's/MA/Mass/' list s实现替换功能,注意结尾的"/"不能忽略
  9. sed -e 's/ MA/, Mass/' -e 's/ VA/, Visual/' list  可实现多命令的替换功能,被替换和替换之间可用逗号隔开
  10. sed  -e 's/MA/, Mass/p' list 输出原有list内容,同时输出修改后的那行
  11. sed  -n 's/MA/, Mass/p' list  仅仅输出替换后的那行
  12. sed只会缓存一行的内容在模式空间,这样的好处是sed可以处理大文件而不会有任何问题,不像一些编辑器因为要一次性载入文件的一大块内容到缓存中而导致内存不足
  13. 删除功能  d
  14. sed 'd' list删除list内容
  15. sed '1d' list 删除list中第一行内容
  16. sed '$d' list 删除list中最后一行内容
  17. sed '/MA/d' list删除list中含有MA的行
  18. 通过指定地址对可以删除该范围内的所有行,例如删除第3行到最后一行:

    <span class="pln">$ sed </span><span class="str" style="color: rgb(221, 17, 68);">'2,$d'</span><span class="pln"> list </span><span class="typ" style="color: rgb(68, 85, 136);">John</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Daggett</span><span class="pun">,</span><span class="pln"> </span><span class="lit" style="color: rgb(68, 85, 136);">341</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">King</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Road</span><span class="pun">,</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Plymouth</span><span class="pln"> MA</span>

    使用正则匹配,删除从包含Alice的行开始到包含Hubert的行结束的所有行:

    <span class="pln">$ sed </span><span class="str" style="color: rgb(221, 17, 68);">'/Alice/,/Hubert/d'</span><span class="pln"> list </span><span class="typ" style="color: rgb(68, 85, 136);">John</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Daggett</span><span class="pun">,</span><span class="pln"> </span><span class="lit" style="color: rgb(68, 85, 136);">341</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">King</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Road</span><span class="pun">,</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Plymouth</span><span class="pln"> MA</span><span class="typ" style="color: rgb(68, 85, 136);">Amy</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Wilde</span><span class="pun">,</span><span class="pln"> </span><span class="lit" style="color: rgb(68, 85, 136);">334</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Bayshore</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Pkwy</span><span class="pun">,</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Mountain</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">View</span><span class="pln"> CA</span><span class="typ" style="color: rgb(68, 85, 136);">Sal</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Carpenter</span><span class="pun">,</span><span class="pln"> </span><span class="lit" style="color: rgb(68, 85, 136);">73</span><span class="pln"> </span><span class="lit" style="color: rgb(68, 85, 136);">6th</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Street</span><span class="pun">,</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Boston</span><span class="pln"> MA</span>

    当然,行号和地址对是可以混用的:

    <span class="pln">$ sed </span><span class="str" style="color: rgb(221, 17, 68);">'2,/Hubert/d'</span><span class="pln"> list </span><span class="typ" style="color: rgb(68, 85, 136);">John</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Daggett</span><span class="pun">,</span><span class="pln"> </span><span class="lit" style="color: rgb(68, 85, 136);">341</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">King</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Road</span><span class="pun">,</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Plymouth</span><span class="pln"> MA</span><span class="typ" style="color: rgb(68, 85, 136);">Amy</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Wilde</span><span class="pun">,</span><span class="pln"> </span><span class="lit" style="color: rgb(68, 85, 136);">334</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Bayshore</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Pkwy</span><span class="pun">,</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Mountain</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">View</span><span class="pln"> CA</span><span class="typ" style="color: rgb(68, 85, 136);">Sal</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Carpenter</span><span class="pun">,</span><span class="pln"> </span><span class="lit" style="color: rgb(68, 85, 136);">73</span><span class="pln"> </span><span class="lit" style="color: rgb(68, 85, 136);">6th</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Street</span><span class="pun">,</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Boston</span><span class="pln"> MA</span>

    如果在地址后面指定感叹号(!),则会将命令应用到不匹配该地址的行:

    <span class="pln">$ sed </span><span class="str" style="color: rgb(221, 17, 68);">'2,/Hubert/!d'</span><span class="pln"> list </span><span class="typ" style="color: rgb(68, 85, 136);">Alice</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Ford</span><span class="pun">,</span><span class="pln"> </span><span class="lit" style="color: rgb(68, 85, 136);">22</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">East</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Broadway</span><span class="pun">,</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Richmond</span><span class="pln"> VA</span><span class="typ" style="color: rgb(68, 85, 136);">Orville</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Thomas</span><span class="pun">,</span><span class="pln"> </span><span class="lit" style="color: rgb(68, 85, 136);">11345</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Oak</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Bridge</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Road</span><span class="pun">,</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Tulsa</span><span class="pln"> OK</span><span class="typ" style="color: rgb(68, 85, 136);">Terry</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Kalkas</span><span class="pun">,</span><span class="pln"> </span><span class="lit" style="color: rgb(68, 85, 136);">402</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Lans</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Road</span><span class="pun">,</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Beaver</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Falls</span><span class="pln"> PA</span><span class="typ" style="color: rgb(68, 85, 136);">Eric</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Adams</span><span class="pun">,</span><span class="pln"> </span><span class="lit" style="color: rgb(68, 85, 136);">20</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Post</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Road</span><span class="pun">,</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Sudbury</span><span class="pln"> MA</span><span class="typ" style="color: rgb(68, 85, 136);">Hubert</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Sims</span><span class="pun">,</span><span class="pln"> </span><span class="lit" style="color: rgb(68, 85, 136);">328A</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Brook</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Road</span><span class="pun">,</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Roanoke</span><span class="pln"> VA</span>

    要执行多个编辑命令要怎么办?sed中可以用{}来组合命令,就好比编程语言中的语句块,例如:

    <span class="pln">$ sed </span><span class="pun">-</span><span class="pln">n </span><span class="str" style="color: rgb(221, 17, 68);">'1,4{s/ MA/, Massachusetts/;s/ PA/, Pennsylvania/;p}'</span><span class="pln"> list </span><span class="typ" style="color: rgb(68, 85, 136);">John</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Daggett</span><span class="pun">,</span><span class="pln"> </span><span class="lit" style="color: rgb(68, 85, 136);">341</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">King</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Road</span><span class="pun">,</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Plymouth</span><span class="pun">,</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Massachusetts</span><span class="pln"></span><span class="typ" style="color: rgb(68, 85, 136);">Alice</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Ford</span><span class="pun">,</span><span class="pln"> </span><span class="lit" style="color: rgb(68, 85, 136);">22</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">East</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Broadway</span><span class="pun">,</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Richmond</span><span class="pln"> VA</span><span class="typ" style="color: rgb(68, 85, 136);">Orville</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Thomas</span><span class="pun">,</span><span class="pln"> </span><span class="lit" style="color: rgb(68, 85, 136);">11345</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Oak</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Bridge</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Road</span><span class="pun">,</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Tulsa</span><span class="pln"> OK</span><span class="typ" style="color: rgb(68, 85, 136);">Terry</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Kalkas</span><span class="pun">,</span><span class="pln"> </span><span class="lit" style="color: rgb(68, 85, 136);">402</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Lans</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Road</span><span class="pun">,</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Beaver</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Falls</span><span class="pun">,</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Pennsylvania</span>

    书中说,对于sed编辑命令的语法有两种约定,分别是

    [address]command               # 第一种[line-address]command          # 第二种

    第一种[address]是指可以为任意地址包括地址对,第二种[line-address]是指只能为单个地址。文中指出,例如i(后方插入命令)、a(前方追加命令)以及=(打印行号命令)等都属于第二种命令

    以下是要介绍的全部基础命令:

    名称命令语法说明替换s[address]s/pattern/replacement/flags替换匹配的内容删除d[address]d删除匹配的行插入i[line-address]i\

    text在匹配行的前方插入文本追加a[line-address]a\

    text在匹配行的后方插入文本行替换c[address]c\

    text将匹配的行替换成文本text打印行p[address]p打印在模式空间中的行打印行号=[address]=打印当前行行号打印行l[address]l打印在模式空间中的行,同时显示控制字符转换字符y[address]y/SET1/SET2/将SET1中出现的字符替换成SET2中对应位置的字符读取下一行n[address]n将下一行的内容读取到模式空间读文件r[line-address]r file将指定的文件读取到匹配行之后写文件w[address]w file将匹配地址的所有行输出到指定的文件中退出q[line-address]q读取到匹配的行之后即退出

    替换命令: s

    替换命令的语法是:

    [address]s/pattern/replacement/flags

    其中[address]是指地址,pattern是替换命令的匹配表达式,replacement则是对应的替换内容,flags是指替换的标志位,它可以包含以下一个或者多个值:

    • n: 一个数字(取值范围1-512),表明仅替换前n个被pattern匹配的内容;
    • g: 表示全局替换,替换所有被pattern匹配的内容;
    • p: 仅当行被pattern匹配时,打印模式空间的内容;
    • w file:仅当行被pattern匹配时,将模式空间的内容输出到文件file中;

    如果flags为空,则默认替换第一次匹配:

    <span class="pln">$ echo </span><span class="str" style="color: rgb(221, 17, 68);">"column1 column2 column3 column4"</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> sed </span><span class="str" style="color: rgb(221, 17, 68);">'s/ /;/'</span><span class="pln">column1</span><span class="pun">;</span><span class="pln">column2 column3 column4</span>

    如果flags中包含g,则表示全局匹配:

    <span class="pln">$ echo </span><span class="str" style="color: rgb(221, 17, 68);">"column1 column2 column3 column4"</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> sed </span><span class="str" style="color: rgb(221, 17, 68);">'s/ /;/g'</span><span class="pln">column1</span><span class="pun">;</span><span class="pln">column2</span><span class="pun">;</span><span class="pln">column3</span><span class="pun">;</span><span class="pln">column4</span>

    如果flags中明确指定替换第n次的匹配,例如n=2:

    <span class="pln">$ echo </span><span class="str" style="color: rgb(221, 17, 68);">"column1 column2 column3 column4"</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> sed </span><span class="str" style="color: rgb(221, 17, 68);">'s/ /;/2'</span><span class="pln">column1 column2</span><span class="pun">;</span><span class="pln">column3 column4</span>

    当替换命令的pattern与地址部分是一样的时候,比如/regexp/s/regexp/replacement/可以省略替换命令中的pattern部分,这在单个编辑命令的情况下没多大用处,但是在组合命令的场景下还是能省不少功夫的,例如下面是摘自文中的一个段落:

    The substitute command is applied to the lines matching the address. If noaddress is specified, it is applied to all lines that match the pattern, aregular expression. If a regular expression is supplied as an address, and nopattern is specified, the substitute command matches what is matched by theaddress.  This can be useful when the substitute command is one of multiplecommands applied at the same address. For an example, see the section "CheckingOut Reference Pages" later in this chapter.

    现在要在substitute command后面增加("s"),同时在被修改的行前面增加+号,以下是使用的sed命令:

    <span class="pln">$ sed </span><span class="str" style="color: rgb(221, 17, 68);">'/substitute command/{s//&("s")/;s/^/+ /}'</span><span class="pln"> paragraph</span><span class="pun">.</span><span class="pln">txt </span>

    这里我们用到了组合命令,并且地址匹配的部分和第一个替换命令的匹配部分是一样的,所以后者我们省略了,在replacement部分用到了&这个元字符,它代表之前匹配的内容,这点我们在后面介绍。执行后的结果为:

    + The substitute command("s") is applied to the lines matching the address. If noaddress is specified, it is applied to all lines that match the pattern, aregular expression. If a regular expression is supplied as an address, and no+ pattern is specified, the substitute command("s") matches what is matched by the+ address.  This can be useful when the substitute command("s") is one of multiplecommands applied at the same address. For an example, see the section "CheckingOut Reference Pages" later in this chapter.

    替换命令的一个技巧是中间的分隔符是可以更改的(这个技巧我们在简洁的Bash编程技巧续篇 - 5. 你知道sed的这个特性吗?中也曾经介绍过),这个技巧在有些地方非常有用,比如路径替换,下面是采用默认的分隔符和使用感叹号作为分隔符的对比:

    <span class="pln">$ find </span><span class="pun">/</span><span class="pln">usr</span><span class="pun">/</span><span class="kwd">local</span><span class="pln"> </span><span class="pun">-</span><span class="pln">maxdepth </span><span class="lit" style="color: rgb(68, 85, 136);">2</span><span class="pln"> </span><span class="pun">-</span><span class="pln">type d </span><span class="pun">|</span><span class="pln"> sed </span><span class="str" style="color: rgb(221, 17, 68);">'s/\/usr\/local\/man/\/usr\/share\/man/'</span><span class="pln">$ find </span><span class="pun">/</span><span class="pln">usr</span><span class="pun">/</span><span class="kwd">local</span><span class="pln"> </span><span class="pun">-</span><span class="pln">maxdepth </span><span class="lit" style="color: rgb(68, 85, 136);">2</span><span class="pln"> </span><span class="pun">-</span><span class="pln">type d </span><span class="pun">|</span><span class="pln"> sed </span><span class="str" style="color: rgb(221, 17, 68);">'s!/usr/local/man!/usr/share/man!'</span>

    替换命令中还有一个很重要的部分——replacement(替换内容),即将匹配的部分替换成replacement。在replacemnt部分中也有几个特殊的元字符,它们分别是:

    • &: 被pattern匹配的内容;
    • \num: 被pattern匹配的第num个分组(正则表达式中的概念,\(..\)括起来的部分称为分组;
    • \: 转义符号,用来转义&,\, 回车等符号

    &元字符我们已经在上面的例子中介绍过,这里举个例子介绍下\num的用法。在Linux系统中,默认都开了几个tty可以让你切换(ctrl+alt+1, ctrl+alt+2 ...),例如CentOS 6.0+的系统默认是6个:

    <span class="pun">[</span><span class="pln">root@localhost </span><span class="pun">~]</span><span class="com" style="color: rgb(153, 153, 136);"># grep -B 1 ACTIVE_CONSOLES /etc/sysconfig/init </span><span class="pln"></span><span class="com" style="color: rgb(153, 153, 136);"># What ttys should gettys be started on?</span><span class="pln">ACTIVE_CONSOLES</span><span class="pun">=</span><span class="str" style="color: rgb(221, 17, 68);">/dev/</span><span class="pln">tty</span><span class="pun">[</span><span class="lit" style="color: rgb(68, 85, 136);">1</span><span class="pun">-</span><span class="lit" style="color: rgb(68, 85, 136);">6</span><span class="pun">]</span>

    可以通过修改上面的配置来减少开机启动的时候创建的tty个数,比如我们只想要2个:

    <span class="pun">[</span><span class="pln">root@localhost </span><span class="pun">~]</span><span class="com" style="color: rgb(153, 153, 136);"># sed -r -i 's!(ACTIVE_CONSOLES=/dev/tty\[1-)6]!\12]!' /etc/sysconfig/init </span><span class="pln">ACTIVE_CONSOLES</span><span class="pun">=</span><span class="str" style="color: rgb(221, 17, 68);">/dev/</span><span class="pln">tty</span><span class="pun">[</span><span class="lit" style="color: rgb(68, 85, 136);">1</span><span class="pun">-</span><span class="lit" style="color: rgb(68, 85, 136);">2</span><span class="pun">]</span>

    其中-i参数表示直接修改原文件,-r参数是指使用扩展的正则表达式(ERE),扩展的正则表达式中分组的括号不需要用反斜杠转义"(ACTIVE_CONSOLES=/dev/tty\[1-)",这里[是有特殊含义的(表示字符组),所以需要转义。在替换的内容中使用\1来引用这个匹配的分组内容,1代表分组的编号,表示第一个分组。

    删除命令: d

    删除命令的语法是:

    [address]d

    删除命令可以用于删除多行内容,例如1,3d会删除1到3行。删除命令会将模式空间中的内容全部删除,并且导致后续命令不会执行并且读入新行,因为当前模式空间的内容已经为空。我们可以试试:

    <span class="pln">$ sed </span><span class="str" style="color: rgb(221, 17, 68);">'2,${d;=}'</span><span class="pln"> list</span><span class="typ" style="color: rgb(68, 85, 136);">John</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Daggett</span><span class="pun">,</span><span class="pln"> </span><span class="lit" style="color: rgb(68, 85, 136);">341</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">King</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Road</span><span class="pun">,</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Plymouth</span><span class="pln"> MA</span>

    以上命令尝试在删除第2行到最后一行之后,打印当前行号(=),但是事实上并没有执行该命令。

    插入行/追加行/替换行命令: i/a/c

    这三个命令的语法如下所示:

    # Append 追加[line-address]a\text# Insert 插入line-address]i\text# Change 行替换 [address]c\text

    以上三个命令,行替换命令(c)允许地址为多个地址,其余两个都只允许单个地址(注:在ArchLinux上测试表明,追加和插入命令都允许多个地址,sed版本为GNU sed version 4.2.1

    追加命令是指在匹配的行后面插入文本text;相反地,插入命令是指匹配的行前面插入文本text;最后,行替换命令会将匹配的行替换成文本text。文本text并没有被添加到模式空间,而是直接输出到屏幕,因此后续的命令也不会应用到添加的文本上。注意,即使使用-n参数也无法抑制添加的文本的输出。

    我们用实际的例子来简单介绍下这三个命令的用法,依然用最初的文本list:

    <span class="pln">$ cat list</span><span class="typ" style="color: rgb(68, 85, 136);">John</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Daggett</span><span class="pun">,</span><span class="pln"> </span><span class="lit" style="color: rgb(68, 85, 136);">341</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">King</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Road</span><span class="pun">,</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Plymouth</span><span class="pln"> MA</span><span class="typ" style="color: rgb(68, 85, 136);">Alice</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Ford</span><span class="pun">,</span><span class="pln"> </span><span class="lit" style="color: rgb(68, 85, 136);">22</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">East</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Broadway</span><span class="pun">,</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Richmond</span><span class="pln"> VA</span><span class="typ" style="color: rgb(68, 85, 136);">Orville</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Thomas</span><span class="pun">,</span><span class="pln"> </span><span class="lit" style="color: rgb(68, 85, 136);">11345</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Oak</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Bridge</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Road</span><span class="pun">,</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Tulsa</span><span class="pln"> OK</span><span class="typ" style="color: rgb(68, 85, 136);">Terry</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Kalkas</span><span class="pun">,</span><span class="pln"> </span><span class="lit" style="color: rgb(68, 85, 136);">402</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Lans</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Road</span><span class="pun">,</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Beaver</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Falls</span><span class="pln"> PA</span><span class="typ" style="color: rgb(68, 85, 136);">Eric</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Adams</span><span class="pun">,</span><span class="pln"> </span><span class="lit" style="color: rgb(68, 85, 136);">20</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Post</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Road</span><span class="pun">,</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Sudbury</span><span class="pln"> MA</span><span class="typ" style="color: rgb(68, 85, 136);">Hubert</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Sims</span><span class="pun">,</span><span class="pln"> </span><span class="lit" style="color: rgb(68, 85, 136);">328A</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Brook</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Road</span><span class="pun">,</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Roanoke</span><span class="pln"> VA</span><span class="typ" style="color: rgb(68, 85, 136);">Amy</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Wilde</span><span class="pun">,</span><span class="pln"> </span><span class="lit" style="color: rgb(68, 85, 136);">334</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Bayshore</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Pkwy</span><span class="pun">,</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Mountain</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">View</span><span class="pln"> CA</span><span class="typ" style="color: rgb(68, 85, 136);">Sal</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Carpenter</span><span class="pun">,</span><span class="pln"> </span><span class="lit" style="color: rgb(68, 85, 136);">73</span><span class="pln"> </span><span class="lit" style="color: rgb(68, 85, 136);">6th</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Street</span><span class="pun">,</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Boston</span><span class="pln"> MA</span>

    现在,我们要在第2行后面添加'------':

    <span class="pln">$ sed </span><span class="str" style="color: rgb(221, 17, 68);">'2a\--------------------------------------'</span><span class="pln"> list</span><span class="typ" style="color: rgb(68, 85, 136);">John</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Daggett</span><span class="pun">,</span><span class="pln"> </span><span class="lit" style="color: rgb(68, 85, 136);">341</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">King</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Road</span><span class="pun">,</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Plymouth</span><span class="pln"> MA</span><span class="typ" style="color: rgb(68, 85, 136);">Alice</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Ford</span><span class="pun">,</span><span class="pln"> </span><span class="lit" style="color: rgb(68, 85, 136);">22</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">East</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Broadway</span><span class="pun">,</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Richmond</span><span class="pln"> VA</span><span class="pun">--------------------------------------</span><span class="pln"></span><span class="typ" style="color: rgb(68, 85, 136);">Orville</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Thomas</span><span class="pun">,</span><span class="pln"> </span><span class="lit" style="color: rgb(68, 85, 136);">11345</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Oak</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Bridge</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Road</span><span class="pun">,</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Tulsa</span><span class="pln"> OK</span><span class="typ" style="color: rgb(68, 85, 136);">Terry</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Kalkas</span><span class="pun">,</span><span class="pln"> </span><span class="lit" style="color: rgb(68, 85, 136);">402</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Lans</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Road</span><span class="pun">,</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Beaver</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Falls</span><span class="pln"> PA</span><span class="typ" style="color: rgb(68, 85, 136);">Eric</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Adams</span><span class="pun">,</span><span class="pln"> </span><span class="lit" style="color: rgb(68, 85, 136);">20</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Post</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Road</span><span class="pun">,</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Sudbury</span><span class="pln"> MA</span><span class="typ" style="color: rgb(68, 85, 136);">Hubert</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Sims</span><span class="pun">,</span><span class="pln"> </span><span class="lit" style="color: rgb(68, 85, 136);">328A</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Brook</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Road</span><span class="pun">,</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Roanoke</span><span class="pln"> VA</span><span class="typ" style="color: rgb(68, 85, 136);">Amy</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Wilde</span><span class="pun">,</span><span class="pln"> </span><span class="lit" style="color: rgb(68, 85, 136);">334</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Bayshore</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Pkwy</span><span class="pun">,</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Mountain</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">View</span><span class="pln"> CA</span><span class="typ" style="color: rgb(68, 85, 136);">Sal</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Carpenter</span><span class="pun">,</span><span class="pln"> </span><span class="lit" style="color: rgb(68, 85, 136);">73</span><span class="pln"> </span><span class="lit" style="color: rgb(68, 85, 136);">6th</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Street</span><span class="pun">,</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Boston</span><span class="pln"> MA</span>

    或者可以在第3行之前插入:

    <span class="pln">$ sed </span><span class="str" style="color: rgb(221, 17, 68);">'3i\--------------------------------------'</span><span class="pln"> list</span><span class="typ" style="color: rgb(68, 85, 136);">John</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Daggett</span><span class="pun">,</span><span class="pln"> </span><span class="lit" style="color: rgb(68, 85, 136);">341</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">King</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Road</span><span class="pun">,</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Plymouth</span><span class="pln"> MA</span><span class="typ" style="color: rgb(68, 85, 136);">Alice</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Ford</span><span class="pun">,</span><span class="pln"> </span><span class="lit" style="color: rgb(68, 85, 136);">22</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">East</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Broadway</span><span class="pun">,</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Richmond</span><span class="pln"> VA</span><span class="pun">--------------------------------------</span><span class="pln"></span><span class="typ" style="color: rgb(68, 85, 136);">Orville</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Thomas</span><span class="pun">,</span><span class="pln"> </span><span class="lit" style="color: rgb(68, 85, 136);">11345</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Oak</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Bridge</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Road</span><span class="pun">,</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Tulsa</span><span class="pln"> OK</span><span class="typ" style="color: rgb(68, 85, 136);">Terry</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Kalkas</span><span class="pun">,</span><span class="pln"> </span><span class="lit" style="color: rgb(68, 85, 136);">402</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Lans</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Road</span><span class="pun">,</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Beaver</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Falls</span><span class="pln"> PA</span><span class="typ" style="color: rgb(68, 85, 136);">Eric</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Adams</span><span class="pun">,</span><span class="pln"> </span><span class="lit" style="color: rgb(68, 85, 136);">20</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Post</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Road</span><span class="pun">,</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Sudbury</span><span class="pln"> MA</span><span class="typ" style="color: rgb(68, 85, 136);">Hubert</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Sims</span><span class="pun">,</span><span class="pln"> </span><span class="lit" style="color: rgb(68, 85, 136);">328A</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Brook</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Road</span><span class="pun">,</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Roanoke</span><span class="pln"> VA</span><span class="typ" style="color: rgb(68, 85, 136);">Amy</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Wilde</span><span class="pun">,</span><span class="pln"> </span><span class="lit" style="color: rgb(68, 85, 136);">334</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Bayshore</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Pkwy</span><span class="pun">,</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Mountain</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">View</span><span class="pln"> CA</span><span class="typ" style="color: rgb(68, 85, 136);">Sal</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Carpenter</span><span class="pun">,</span><span class="pln"> </span><span class="lit" style="color: rgb(68, 85, 136);">73</span><span class="pln"> </span><span class="lit" style="color: rgb(68, 85, 136);">6th</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Street</span><span class="pun">,</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Boston</span><span class="pln"> MA</span>

    我们来测试下文本是否确实没有添加到模式空间,因为模式空间中的内容默认是会打印到屏幕的:

    <span class="pln">$ sed </span><span class="pun">-</span><span class="pln">n </span><span class="str" style="color: rgb(221, 17, 68);">'2a\--------------------------------------'</span><span class="pln"> list</span><span class="pun">--------------------------------------</span>

    通过-n参数来抑制输出后发现插入的内容依然被输出,所以可以判定插入的内容没有被添加到模式空间。

    使用行替换命令将第2行到最后一行的内容全部替换成'----':

    <span class="pln">$ sed </span><span class="str" style="color: rgb(221, 17, 68);">'2,$c\--------------------------------------'</span><span class="pln"> list</span><span class="typ" style="color: rgb(68, 85, 136);">John</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Daggett</span><span class="pun">,</span><span class="pln"> </span><span class="lit" style="color: rgb(68, 85, 136);">341</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">King</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Road</span><span class="pun">,</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Plymouth</span><span class="pln"> MA</span><span class="pun">--------------------------------------</span>

    打印命令: p/l/=

    这里纯粹的打印命令应该是指p,但是因为后两者(l和=)和p差不多,并且相对都比较简单,所以这里放到一起介绍。

    这三个命令的语法是:

    [address]p[address]=[address]l

    p命令用于打印模式空间的内容,例如打印list文件的第一行:

    <span class="pln">$ sed </span><span class="pun">-</span><span class="pln">n </span><span class="str" style="color: rgb(221, 17, 68);">'1p'</span><span class="pln"> list</span><span class="typ" style="color: rgb(68, 85, 136);">John</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Daggett</span><span class="pun">,</span><span class="pln"> </span><span class="lit" style="color: rgb(68, 85, 136);">341</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">King</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Road</span><span class="pun">,</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Plymouth</span><span class="pln"> MA</span>

    l命令类似p命令,不过会显示控制字符,这个命令和vim的list命令相似,例如:

    <span class="pln">$ echo </span><span class="str" style="color: rgb(221, 17, 68);">"column1 column2 column3^M"</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> sed </span><span class="pun">-</span><span class="pln">n </span><span class="str" style="color: rgb(221, 17, 68);">'l'</span><span class="pln">column1\tcolumn2\tcolumn3\r$</span>

    =命令显示当前行行号,例如:

    <span class="pln">$ sed </span><span class="str" style="color: rgb(221, 17, 68);">'='</span><span class="pln"> list</span><span class="lit" style="color: rgb(68, 85, 136);">1</span><span class="pln"></span><span class="typ" style="color: rgb(68, 85, 136);">John</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Daggett</span><span class="pun">,</span><span class="pln"> </span><span class="lit" style="color: rgb(68, 85, 136);">341</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">King</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Road</span><span class="pun">,</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Plymouth</span><span class="pln"> MA</span><span class="lit" style="color: rgb(68, 85, 136);">2</span><span class="pln"></span><span class="typ" style="color: rgb(68, 85, 136);">Alice</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Ford</span><span class="pun">,</span><span class="pln"> </span><span class="lit" style="color: rgb(68, 85, 136);">22</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">East</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Broadway</span><span class="pun">,</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Richmond</span><span class="pln"> VA</span><span class="lit" style="color: rgb(68, 85, 136);">3</span><span class="pln"></span><span class="typ" style="color: rgb(68, 85, 136);">Orville</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Thomas</span><span class="pun">,</span><span class="pln"> </span><span class="lit" style="color: rgb(68, 85, 136);">11345</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Oak</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Bridge</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Road</span><span class="pun">,</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Tulsa</span><span class="pln"> OK</span><span class="lit" style="color: rgb(68, 85, 136);">4</span><span class="pln"></span><span class="typ" style="color: rgb(68, 85, 136);">Terry</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Kalkas</span><span class="pun">,</span><span class="pln"> </span><span class="lit" style="color: rgb(68, 85, 136);">402</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Lans</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Road</span><span class="pun">,</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Beaver</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Falls</span><span class="pln"> PA</span><span class="lit" style="color: rgb(68, 85, 136);">5</span><span class="pln"></span><span class="typ" style="color: rgb(68, 85, 136);">Eric</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Adams</span><span class="pun">,</span><span class="pln"> </span><span class="lit" style="color: rgb(68, 85, 136);">20</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Post</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Road</span><span class="pun">,</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Sudbury</span><span class="pln"> MA</span><span class="lit" style="color: rgb(68, 85, 136);">6</span><span class="pln"></span><span class="typ" style="color: rgb(68, 85, 136);">Hubert</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Sims</span><span class="pun">,</span><span class="pln"> </span><span class="lit" style="color: rgb(68, 85, 136);">328A</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Brook</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Road</span><span class="pun">,</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Roanoke</span><span class="pln"> VA</span><span class="lit" style="color: rgb(68, 85, 136);">7</span><span class="pln"></span><span class="typ" style="color: rgb(68, 85, 136);">Amy</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Wilde</span><span class="pun">,</span><span class="pln"> </span><span class="lit" style="color: rgb(68, 85, 136);">334</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Bayshore</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Pkwy</span><span class="pun">,</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Mountain</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">View</span><span class="pln"> CA</span><span class="lit" style="color: rgb(68, 85, 136);">8</span><span class="pln"></span><span class="typ" style="color: rgb(68, 85, 136);">Sal</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Carpenter</span><span class="pun">,</span><span class="pln"> </span><span class="lit" style="color: rgb(68, 85, 136);">73</span><span class="pln"> </span><span class="lit" style="color: rgb(68, 85, 136);">6th</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Street</span><span class="pun">,</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Boston</span><span class="pln"> MA</span>

    转换命令: y

    转换命令的语法是:

    [address]y/SET1/SET2/

    它的作用是在匹配的行上,将SET1中出现的字符替换成SET2中对应位置的字符,例如1,3y/abc/xyz/会将1到3行中出现的a替换成x,b替换成y,c替换成z。是不是觉得这个功能很熟悉,其实这一点和tr命令是一样的。可以通过y命令将小写字符替换成大写字符,不过命令比较长:

    <span class="pln">$ echo </span><span class="str" style="color: rgb(221, 17, 68);">"hello, world"</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> sed </span><span class="str" style="color: rgb(221, 17, 68);">'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'</span><span class="pln">HELLO</span><span class="pun">,</span><span class="pln"> WORLD</span>

    使用tr命令来转换成大写:

    <span class="pln">$ echo </span><span class="str" style="color: rgb(221, 17, 68);">"hello, world"</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> tr a</span><span class="pun">-</span><span class="pln">z A</span><span class="pun">-</span><span class="pln">Z                                                    HELLO</span><span class="pun">,</span><span class="pln"> WORLD</span>

    取下一行命令: n

    取下一行命令的语法为:

    [address]n

    n命令为将下一行的内容提前读入,并且将之前读入的行(在模式空间中的行)输出到屏幕,然后后续的命令会应用到新读入的行上。因此n命令也会同d命令一样改变sed的控制流程。

    书中给出了一个例子来介绍n的用法,假设有这么一个文本:

    <span class="pln">$ cat text</span><span class="pun">.</span><span class="pln">H1 </span><span class="str" style="color: rgb(221, 17, 68);">"On Egypt"</span><span class="pln"></span><span class="typ" style="color: rgb(68, 85, 136);">Napoleon</span><span class="pun">,</span><span class="pln"> pointing to the </span><span class="typ" style="color: rgb(68, 85, 136);">Pyramids</span><span class="pun">,</span><span class="pln"> said to his troops</span><span class="pun">:</span><span class="pln"></span><span class="str" style="color: rgb(221, 17, 68);">"Soldiers, forty centuries have their eyes upon you."</span>

    现在要将.H1后面的空行删除:

    <span class="pln">$ sed </span><span class="str" style="color: rgb(221, 17, 68);">'/.H1/{n;/^$/d}'</span><span class="pln"> text</span><span class="pun">.</span><span class="pln">H1 </span><span class="str" style="color: rgb(221, 17, 68);">"On Egypt"</span><span class="pln"></span><span class="typ" style="color: rgb(68, 85, 136);">Napoleon</span><span class="pun">,</span><span class="pln"> pointing to the </span><span class="typ" style="color: rgb(68, 85, 136);">Pyramids</span><span class="pun">,</span><span class="pln"> said to his troops</span><span class="pun">:</span><span class="pln"></span><span class="str" style="color: rgb(221, 17, 68);">"Soldiers, forty centuries have their eyes upon you."</span>

    读写文件命令: r/w

    读写文件命令的语法是:

    [line-address]r file[address]w file

    读命令将指定的文件读取到匹配行之后,并且输出到屏幕,这点类似追加命令(a)。我们以书中的例子来讲解读文件命令。假设有一个文件text:

    <span class="pln">$ cat text</span><span class="typ" style="color: rgb(68, 85, 136);">For</span><span class="pln"> service</span><span class="pun">,</span><span class="pln"> contact any of the following companies</span><span class="pun">:</span><span class="pln"></span><span class="pun">[</span><span class="typ" style="color: rgb(68, 85, 136);">Company</span><span class="pun">-</span><span class="pln">list</span><span class="pun">]</span><span class="pln"></span><span class="typ" style="color: rgb(68, 85, 136);">Thank</span><span class="pln"> you</span><span class="pun">.</span>

    同时我们有一个包含公司名称列表的文件company.list:

    <span class="pln">$ cat company</span><span class="pun">.</span><span class="pln">list </span><span class="typ" style="color: rgb(68, 85, 136);">Allied</span><span class="pln"></span><span class="typ" style="color: rgb(68, 85, 136);">Mayflower</span><span class="pln"></span><span class="typ" style="color: rgb(68, 85, 136);">United</span>

    现在我们要将company.list的内容读取到[Company-list]之后:

    <span class="pln">$ sed </span><span class="str" style="color: rgb(221, 17, 68);">'/^\[Company-list]/r company.list'</span><span class="pln"> text</span><span class="typ" style="color: rgb(68, 85, 136);">For</span><span class="pln"> service</span><span class="pun">,</span><span class="pln"> contact any of the following companies</span><span class="pun">:</span><span class="pln"></span><span class="pun">[</span><span class="typ" style="color: rgb(68, 85, 136);">Company</span><span class="pun">-</span><span class="pln">list</span><span class="pun">]</span><span class="pln"></span><span class="typ" style="color: rgb(68, 85, 136);">Allied</span><span class="pln"></span><span class="typ" style="color: rgb(68, 85, 136);">Mayflower</span><span class="pln"></span><span class="typ" style="color: rgb(68, 85, 136);">United</span><span class="pln"></span><span class="typ" style="color: rgb(68, 85, 136);">Thank</span><span class="pln"> you</span><span class="pun">.</span>

    更好的处理应当是用公司名称命令替换[Company-list],因此我们还需要删除[Company-list]这一行:

    <span class="pln">$ sed </span><span class="str" style="color: rgb(221, 17, 68);">'/^\[Company-list]/r company.list;/^\[Company-list]/d;'</span><span class="pln"> text</span><span class="typ" style="color: rgb(68, 85, 136);">For</span><span class="pln"> service</span><span class="pun">,</span><span class="pln"> contact any of the following companies</span><span class="pun">:</span><span class="pln"></span><span class="pun">[</span><span class="typ" style="color: rgb(68, 85, 136);">Company</span><span class="pun">-</span><span class="pln">list</span><span class="pun">]</span><span class="pln"></span><span class="typ" style="color: rgb(68, 85, 136);">Thank</span><span class="pln"> you</span><span class="pun">.</span>

    但是结果我们非但没有删除[Company-list],而且company.list的内容也不见了?这是怎么回事呢?

    下面是我猜测的过程,读文件的命令会将r空格后面的所有内容都当成文件名,即company.list;/^\[Company-list]/d;,然后读取命令的时候发现该文件不存在,但是sed命令读取不存在的文件是不会报错的。所以什么事都没干成。

    我们用-e选项将两个命令分开就正常了:

    <span class="pln">$ sed </span><span class="pun">-</span><span class="pln">e </span><span class="str" style="color: rgb(221, 17, 68);">'/^\[Company-list]/r company.list'</span><span class="pln"> </span><span class="pun">-</span><span class="pln">e </span><span class="str" style="color: rgb(221, 17, 68);">'/^\[Company-list]/d;'</span><span class="pln"> text</span><span class="typ" style="color: rgb(68, 85, 136);">For</span><span class="pln"> service</span><span class="pun">,</span><span class="pln"> contact any of the following companies</span><span class="pun">:</span><span class="pln"></span><span class="typ" style="color: rgb(68, 85, 136);">Allied</span><span class="pln"></span><span class="typ" style="color: rgb(68, 85, 136);">Mayflower</span><span class="pln"></span><span class="typ" style="color: rgb(68, 85, 136);">United</span><span class="pln"></span><span class="typ" style="color: rgb(68, 85, 136);">Thank</span><span class="pln"> you</span><span class="pun">.</span>

    写命令将匹配地址的所有行输出到指定的文件中。假设有一个文件内容如下,前半部分是人名,后半部分是区域名称:

    <span class="pln">$ cat text </span><span class="typ" style="color: rgb(68, 85, 136);">Adams</span><span class="pun">,</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Henrietta</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Northeast</span><span class="pln"></span><span class="typ" style="color: rgb(68, 85, 136);">Banks</span><span class="pun">,</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Freda</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">South</span><span class="pln"></span><span class="typ" style="color: rgb(68, 85, 136);">Dennis</span><span class="pun">,</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Jim</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Midwest</span><span class="pln"></span><span class="typ" style="color: rgb(68, 85, 136);">Garvey</span><span class="pun">,</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Bill</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Northeast</span><span class="pln"></span><span class="typ" style="color: rgb(68, 85, 136);">Jeffries</span><span class="pun">,</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Jane</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">West</span><span class="pln"></span><span class="typ" style="color: rgb(68, 85, 136);">Madison</span><span class="pun">,</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Sylvia</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Midwest</span><span class="pln"></span><span class="typ" style="color: rgb(68, 85, 136);">Sommes</span><span class="pun">,</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Tom</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">South</span>

    现在我们要将不同区域的人名字写到不同的文件中:

    <span class="pln">$ sed </span><span class="str" style="color: rgb(221, 17, 68);">'/Northeast$/w region.northeast> /South$/w region.south> /Midwest$/w region.midwest> /West$/w region.west'</span><span class="pln"> text</span><span class="typ" style="color: rgb(68, 85, 136);">Adams</span><span class="pun">,</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Henrietta</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Northeast</span><span class="pln"></span><span class="typ" style="color: rgb(68, 85, 136);">Banks</span><span class="pun">,</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Freda</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">South</span><span class="pln"></span><span class="typ" style="color: rgb(68, 85, 136);">Dennis</span><span class="pun">,</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Jim</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Midwest</span><span class="pln"></span><span class="typ" style="color: rgb(68, 85, 136);">Garvey</span><span class="pun">,</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Bill</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Northeast</span><span class="pln"></span><span class="typ" style="color: rgb(68, 85, 136);">Jeffries</span><span class="pun">,</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Jane</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">West</span><span class="pln"></span><span class="typ" style="color: rgb(68, 85, 136);">Madison</span><span class="pun">,</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Sylvia</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Midwest</span><span class="pln"></span><span class="typ" style="color: rgb(68, 85, 136);">Sommes</span><span class="pun">,</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Tom</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">South</span>

    查看输出的文件:

    <span class="pln">$ cat region</span><span class="pun">.</span><span class="pln">region</span><span class="pun">.</span><span class="pln">midwest    region</span><span class="pun">.</span><span class="pln">northeast  region</span><span class="pun">.</span><span class="pln">south      region</span><span class="pun">.</span><span class="pln">west $ cat region</span><span class="pun">.</span><span class="pln">midwest     </span><span class="typ" style="color: rgb(68, 85, 136);">Dennis</span><span class="pun">,</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Jim</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Midwest</span><span class="pln"></span><span class="typ" style="color: rgb(68, 85, 136);">Madison</span><span class="pun">,</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Sylvia</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Midwest</span>

    我们也可以试试将所有的w命令放到一起用分号分隔,发现会出下面的错误,它把w空格后面的部分当作文件名,这样就验证了上面的猜测:

    <span class="pln">$ sed </span><span class="str" style="color: rgb(221, 17, 68);">'/Northeast$/w region.northeast;/south$/w region.south;'</span><span class="pln"> textsed</span><span class="pun">:</span><span class="pln"> couldn</span><span class="str" style="color: rgb(221, 17, 68);">'t open file region.northeast;/south$/w region.south;: No such file or directory</span>

    退出命令: q

    退出命令的语法是

    [line-address]q

    当sed读取到匹配的行之后即退出,不会再读入新的行,并且将当前模式空间的内容输出到屏幕。例如打印前3行内容:

    <span class="pln">$ sed </span><span class="str" style="color: rgb(221, 17, 68);">'3q'</span><span class="pln"> list</span><span class="typ" style="color: rgb(68, 85, 136);">John</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Daggett</span><span class="pun">,</span><span class="pln"> </span><span class="lit" style="color: rgb(68, 85, 136);">341</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">King</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Road</span><span class="pun">,</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Plymouth</span><span class="pln"> MA</span><span class="typ" style="color: rgb(68, 85, 136);">Alice</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Ford</span><span class="pun">,</span><span class="pln"> </span><span class="lit" style="color: rgb(68, 85, 136);">22</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">East</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Broadway</span><span class="pun">,</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Richmond</span><span class="pln"> VA</span><span class="typ" style="color: rgb(68, 85, 136);">Orville</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Thomas</span><span class="pun">,</span><span class="pln"> </span><span class="lit" style="color: rgb(68, 85, 136);">11345</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Oak</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Bridge</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Road</span><span class="pun">,</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Tulsa</span><span class="pln"> OK</span>

    打印前3行也可以用p命令:

    <span class="pln">$ sed </span><span class="pun">-</span><span class="pln">n </span><span class="str" style="color: rgb(221, 17, 68);">'3p'</span><span class="pln"> list</span><span class="typ" style="color: rgb(68, 85, 136);">John</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Daggett</span><span class="pun">,</span><span class="pln"> </span><span class="lit" style="color: rgb(68, 85, 136);">341</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">King</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Road</span><span class="pun">,</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Plymouth</span><span class="pln"> MA</span><span class="typ" style="color: rgb(68, 85, 136);">Alice</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Ford</span><span class="pun">,</span><span class="pln"> </span><span class="lit" style="color: rgb(68, 85, 136);">22</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">East</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Broadway</span><span class="pun">,</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Richmond</span><span class="pln"> VA</span><span class="typ" style="color: rgb(68, 85, 136);">Orville</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Thomas</span><span class="pun">,</span><span class="pln"> </span><span class="lit" style="color: rgb(68, 85, 136);">11345</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Oak</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Bridge</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Road</span><span class="pun">,</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Tulsa</span><span class="pln"> OK</span>

    但是对于大文件来说,前者比后者效率更高,因为前者读取到第N行之后就退出了。后者虽然打印了前N行,但是后续的行还是要继续读入,只不会不作处理。

    到此为止,sed基础命令的部分就介绍完了。下面一篇的内容会在最近几天更新上来,主要会介绍sed高级命令。不过一般情况下,会使用基础命令已经差不多了,高级命令不一定需要去了解。

    下面是我整理的一份思维导图(附.xmind文件下载地址):
    sed基础命令

    在上一篇中介绍的基础命令都是面向行的,一般情况下,这种处理并没有什么问题,但是当匹配的内容是错开在两行时就会有问题,最明显的例子就是某些英文单词会被分成两行。

    幸运地是,sed允许将多行内容读取到模式空间,这样你就可以匹配跨越多行的内容。本篇笔记主要介绍这些命令,它们能够创建多行模式空间并且处理之。其中,N/D/P这三个多行命令分别对应于小写的n/d/p命令,后者我们在上一篇已经介绍。它们的功能是类似的,区别在于命令影响的内容不同。例如D命令与d命令同样是删除模式空间的内容,只不过d命令会删除模式空间中所有的内容,而D命令仅会删除模式空间中的第一行。

    读下一行:N

    N命令将下一行的内容读取到当前模式空间,但是下n命令不一样的地方是N命令并没有直接输出当前模式空间中的行,而是把下一行追加到当前模式空间,两行之间用回车符\n连接,如下图所示:

    模式空间包含多行之后,正则表达式的^/$符号的意思就变了,^是匹配模式空间的最开始而非行首,$是匹配模式空间的最后位置而非行尾。

    书中给的第一例子,是替换以下文本中的"Owner and Operator Guide"为"Installation Guide",正如我们在本篇开头说的Owner and Operator Guide跨越在两行:

    Consult Section 3.1 in the Owner and OperatorGuide for a description of the tape drivesavailable on your system.

    我们用N命令试下手:

    <span class="pln">$ sed </span><span class="str" style="color: rgb(221, 17, 68);">'/Operator$/{N;s/Owner and Operator\nGuide/Installation Guide/}'</span><span class="pln"> text</span><span class="typ" style="color: rgb(68, 85, 136);">Consult</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Section</span><span class="pln"> </span><span class="lit" style="color: rgb(68, 85, 136);">3.1</span><span class="pln"> </span><span class="kwd">in</span><span class="pln"> the </span><span class="typ" style="color: rgb(68, 85, 136);">Installation</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Guide</span><span class="pln"> </span><span class="kwd">for</span><span class="pln"> a description of the tape drivesavailable on your system</span><span class="pun">.</span>

    不过这个例子有两个局限:

    • 我们知道Owner and Operator Guide分割的位置;
    • 执行替换命令后,前后两行拼接在一起,导致这行过长;

    第二点,可以这样解决:

    <span class="pln">$ sed </span><span class="str" style="color: rgb(221, 17, 68);">'/Operator$/{N;s/Owner and Operator\nGuide /Installation Guide\n/}'</span><span class="pln"> text</span><span class="typ" style="color: rgb(68, 85, 136);">Consult</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Section</span><span class="pln"> </span><span class="lit" style="color: rgb(68, 85, 136);">3.1</span><span class="pln"> </span><span class="kwd">in</span><span class="pln"> the </span><span class="typ" style="color: rgb(68, 85, 136);">Installation</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Guide</span><span class="pln"></span><span class="kwd">for</span><span class="pln"> a description of the tape drivesavailable on your system</span><span class="pun">.</span>

    现在去掉第1个前提,我们引入更加复杂的测试文本,这段文本中Owner and Operator Guide有位于一行的,也有跨越多行的情况:

    <span class="pln">$ cat text</span><span class="typ" style="color: rgb(68, 85, 136);">Consult</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Section</span><span class="pln"> </span><span class="lit" style="color: rgb(68, 85, 136);">3.1</span><span class="pln"> </span><span class="kwd">in</span><span class="pln"> the </span><span class="typ" style="color: rgb(68, 85, 136);">Owner</span><span class="pln"> </span><span class="kwd">and</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Operator</span><span class="pln"></span><span class="typ" style="color: rgb(68, 85, 136);">Guide</span><span class="pln"> </span><span class="kwd">for</span><span class="pln"> a description of the tape drivesavailable on your system</span><span class="pun">.</span><span class="pln"></span><span class="typ" style="color: rgb(68, 85, 136);">Look</span><span class="pln"> </span><span class="kwd">in</span><span class="pln"> the </span><span class="typ" style="color: rgb(68, 85, 136);">Owner</span><span class="pln"> </span><span class="kwd">and</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Operator</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Guide</span><span class="pln"> shipped </span><span class="kwd">with</span><span class="pln"> your system</span><span class="pun">.</span><span class="pln"></span><span class="typ" style="color: rgb(68, 85, 136);">Two</span><span class="pln"> manuals are provided including the </span><span class="typ" style="color: rgb(68, 85, 136);">Owner</span><span class="pln"> </span><span class="kwd">and</span><span class="pln"></span><span class="typ" style="color: rgb(68, 85, 136);">Operator</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Guide</span><span class="pln"> </span><span class="kwd">and</span><span class="pln"> the </span><span class="typ" style="color: rgb(68, 85, 136);">User</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Guide</span><span class="pun">.</span><span class="pln"></span><span class="typ" style="color: rgb(68, 85, 136);">The</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Owner</span><span class="pln"> </span><span class="kwd">and</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Operator</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Guide</span><span class="pln"> </span><span class="kwd">is</span><span class="pln"> shipped </span><span class="kwd">with</span><span class="pln"> your system</span><span class="pun">.</span>

    相应地修改下之前执行的命令,如下所示:

    <span class="pln">$ sed </span><span class="str" style="color: rgb(221, 17, 68);">'s/Owner and Operator Guide/Installation Guide//Owner/{Ns/ *\n/ /s/Owner and Operator Guide */Installation Guide\/}'</span><span class="pln"> text</span><span class="typ" style="color: rgb(68, 85, 136);">Consult</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Section</span><span class="pln"> </span><span class="lit" style="color: rgb(68, 85, 136);">3.1</span><span class="pln"> </span><span class="kwd">in</span><span class="pln"> the </span><span class="typ" style="color: rgb(68, 85, 136);">Installation</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Guide</span><span class="pln"></span><span class="kwd">for</span><span class="pln"> a description of the tape drivesavailable on your system</span><span class="pun">.</span><span class="pln"></span><span class="typ" style="color: rgb(68, 85, 136);">Look</span><span class="pln"> </span><span class="kwd">in</span><span class="pln"> the </span><span class="typ" style="color: rgb(68, 85, 136);">Installation</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Guide</span><span class="pln"> shipped </span><span class="kwd">with</span><span class="pln"> your system</span><span class="pun">.</span><span class="pln"></span><span class="typ" style="color: rgb(68, 85, 136);">Two</span><span class="pln"> manuals are provided including the </span><span class="typ" style="color: rgb(68, 85, 136);">Installation</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Guide</span><span class="pln"></span><span class="kwd">and</span><span class="pln"> the </span><span class="typ" style="color: rgb(68, 85, 136);">User</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Guide</span><span class="pun">.</span><span class="pln"></span><span class="typ" style="color: rgb(68, 85, 136);">The</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Installation</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Guide</span><span class="pln"> </span><span class="kwd">is</span><span class="pln"> shipped </span><span class="kwd">with</span><span class="pln"> your system</span><span class="pun">.</span>

    这里我们首先将在单行出现的Owner and Operator Guide替换为Installation Guide,然后再寻找匹配Owner的行,匹配后读取下一行的内容到模式空间,并且将中间的换行符替换成空格,最后再替换Owner and Operator Guide。

    解释起来很简单,但是中间还是有些门道的。比如你可能觉得这里最前面的s/Owner and Operator Guide/Installation Guide/命令是多余的,假设你删除这一句:

    <span class="pln">$ sed </span><span class="str" style="color: rgb(221, 17, 68);">'/Owner/{> N> s/ *\n/ /> s/Owner and Operator Guide */Installation Guide\> /> }'</span><span class="pln"> text</span><span class="typ" style="color: rgb(68, 85, 136);">Consult</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Section</span><span class="pln"> </span><span class="lit" style="color: rgb(68, 85, 136);">3.1</span><span class="pln"> </span><span class="kwd">in</span><span class="pln"> the </span><span class="typ" style="color: rgb(68, 85, 136);">Installation</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Guide</span><span class="pln"></span><span class="kwd">for</span><span class="pln"> a description of the tape drivesavailable on your system</span><span class="pun">.</span><span class="pln"></span><span class="typ" style="color: rgb(68, 85, 136);">Look</span><span class="pln"> </span><span class="kwd">in</span><span class="pln"> the </span><span class="typ" style="color: rgb(68, 85, 136);">Installation</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Guide</span><span class="pln">shipped </span><span class="kwd">with</span><span class="pln"> your system</span><span class="pun">.</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Two</span><span class="pln"> manuals are provided including the </span><span class="typ" style="color: rgb(68, 85, 136);">Installation</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Guide</span><span class="pln"></span><span class="kwd">and</span><span class="pln"> the </span><span class="typ" style="color: rgb(68, 85, 136);">User</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Guide</span><span class="pun">.</span><span class="pln"></span><span class="typ" style="color: rgb(68, 85, 136);">The</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Owner</span><span class="pln"> </span><span class="kwd">and</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Operator</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Guide</span><span class="pln"> </span><span class="kwd">is</span><span class="pln"> shipped </span><span class="kwd">with</span><span class="pln"> your system</span><span class="pun">.</span>

    最明显的问题是最后一行没有被替换,原因是当最后一行的被读入到模式空间后,匹配Owner,执行N命令读入下一行,但是因为当前已经是最后一行,所以N读取替换,告诉sed可以退出了,sed也不会继续执行接下来的替换命令(注:书中说最后一行不会被打印输出,我这边测试是会输出的)。所以这里需要在使用N的时候加一个判断,即当前行为最后一行时,不读取下一行的内容:$!N,这一点在很多场合都是有用的,更改后重新执行:

    <span class="pln">$ sed </span><span class="str" style="color: rgb(221, 17, 68);">'/Owner/{> $!N> s/ *\n/ /> s/Owner and Operator Guide */Installation Guide\> /> }'</span><span class="pln"> text</span><span class="typ" style="color: rgb(68, 85, 136);">Consult</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Section</span><span class="pln"> </span><span class="lit" style="color: rgb(68, 85, 136);">3.1</span><span class="pln"> </span><span class="kwd">in</span><span class="pln"> the </span><span class="typ" style="color: rgb(68, 85, 136);">Installation</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Guide</span><span class="pln"></span><span class="kwd">for</span><span class="pln"> a description of the tape drivesavailable on your system</span><span class="pun">.</span><span class="pln"></span><span class="typ" style="color: rgb(68, 85, 136);">Look</span><span class="pln"> </span><span class="kwd">in</span><span class="pln"> the </span><span class="typ" style="color: rgb(68, 85, 136);">Installation</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Guide</span><span class="pln">shipped </span><span class="kwd">with</span><span class="pln"> your system</span><span class="pun">.</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Two</span><span class="pln"> manuals are provided including the </span><span class="typ" style="color: rgb(68, 85, 136);">Installation</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Guide</span><span class="pln"></span><span class="kwd">and</span><span class="pln"> the </span><span class="typ" style="color: rgb(68, 85, 136);">User</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Guide</span><span class="pun">.</span><span class="pln"></span><span class="typ" style="color: rgb(68, 85, 136);">The</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Installation</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Guide</span><span class="pln"></span><span class="kwd">is</span><span class="pln"> shipped </span><span class="kwd">with</span><span class="pln"> your system</span><span class="pun">.</span>

    上面只是为了用例子说明N的用法,可能解决方案未必是最好的。

    删除行:D

    该命令删除模式空间中第一行的内容,而它对应的小d命令删除模式空间的所有内容。D不会导致读入新行,相反它会回到最初的编辑命令,重要应用在模式空间剩余的内容上。

    后面半句开始比较难以理解,用书中的一个例子来解释下。现在我们有一个文本文件,内容如下所示,行之间有空行:

    <span class="pln">$ cat text</span><span class="typ" style="color: rgb(68, 85, 136);">This</span><span class="pln"> line </span><span class="kwd">is</span><span class="pln"> followed </span><span class="kwd">by</span><span class="pln"> </span><span class="lit" style="color: rgb(68, 85, 136);">1</span><span class="pln"> blank line</span><span class="pun">.</span><span class="pln"></span><span class="typ" style="color: rgb(68, 85, 136);">This</span><span class="pln"> line </span><span class="kwd">is</span><span class="pln"> followed </span><span class="kwd">by</span><span class="pln"> </span><span class="lit" style="color: rgb(68, 85, 136);">2</span><span class="pln"> blank lines</span><span class="pun">.</span><span class="pln"></span><span class="typ" style="color: rgb(68, 85, 136);">This</span><span class="pln"> line </span><span class="kwd">is</span><span class="pln"> followed </span><span class="kwd">by</span><span class="pln"> </span><span class="lit" style="color: rgb(68, 85, 136);">3</span><span class="pln"> blank lines</span><span class="pun">.</span><span class="pln"></span><span class="typ" style="color: rgb(68, 85, 136);">This</span><span class="pln"> line </span><span class="kwd">is</span><span class="pln"> followed </span><span class="kwd">by</span><span class="pln"> </span><span class="lit" style="color: rgb(68, 85, 136);">4</span><span class="pln"> blank lines</span><span class="pun">.</span><span class="pln"></span><span class="typ" style="color: rgb(68, 85, 136);">This</span><span class="pln"> </span><span class="kwd">is</span><span class="pln"> the </span><span class="kwd">end</span><span class="pun">.</span>

    现在我们要删除多余的空行,将多个空行缩减成一行。假如我们使用d命令来删除,很简单的逻辑:

    <span class="pln">$ sed </span><span class="str" style="color: rgb(221, 17, 68);">'/^$/{N;/^\n$/d}'</span><span class="pln"> text</span><span class="typ" style="color: rgb(68, 85, 136);">This</span><span class="pln"> line </span><span class="kwd">is</span><span class="pln"> followed </span><span class="kwd">by</span><span class="pln"> </span><span class="lit" style="color: rgb(68, 85, 136);">1</span><span class="pln"> blank line</span><span class="pun">.</span><span class="pln"></span><span class="typ" style="color: rgb(68, 85, 136);">This</span><span class="pln"> line </span><span class="kwd">is</span><span class="pln"> followed </span><span class="kwd">by</span><span class="pln"> </span><span class="lit" style="color: rgb(68, 85, 136);">2</span><span class="pln"> blank lines</span><span class="pun">.</span><span class="pln"></span><span class="typ" style="color: rgb(68, 85, 136);">This</span><span class="pln"> line </span><span class="kwd">is</span><span class="pln"> followed </span><span class="kwd">by</span><span class="pln"> </span><span class="lit" style="color: rgb(68, 85, 136);">3</span><span class="pln"> blank lines</span><span class="pun">.</span><span class="pln"></span><span class="typ" style="color: rgb(68, 85, 136);">This</span><span class="pln"> line </span><span class="kwd">is</span><span class="pln"> followed </span><span class="kwd">by</span><span class="pln"> </span><span class="lit" style="color: rgb(68, 85, 136);">4</span><span class="pln"> blank lines</span><span class="pun">.</span><span class="pln"></span><span class="typ" style="color: rgb(68, 85, 136);">This</span><span class="pln"> </span><span class="kwd">is</span><span class="pln"> the </span><span class="kwd">end</span><span class="pun">.</span>

    我们会发现一个奇怪的结果,奇数个数的相连空行已经被合并成一行,但是偶数个数的却全部被删除了。造成这样的原因需要重新翻译下上面的命令,当匹配一个空行是,将下一行也读取到模式空间,然后若下一行也是空行,则模式空间中的内容应该是\n,因此匹配^\n$,从而执行d命令会将模式空间中的内容清空,结果就是相连的两个空行都被删除。这样就可以理解为什么相连奇数个空行的情况下是正常的,而偶数个数就有问题了。

    这种情况下,我们就应该用D命令来处理,这样做就得到预期的结果了:

    <span class="pln">$ sed </span><span class="str" style="color: rgb(221, 17, 68);">'/^$/{N;/^\n$/D}'</span><span class="pln"> text</span><span class="typ" style="color: rgb(68, 85, 136);">This</span><span class="pln"> line </span><span class="kwd">is</span><span class="pln"> followed </span><span class="kwd">by</span><span class="pln"> </span><span class="lit" style="color: rgb(68, 85, 136);">1</span><span class="pln"> blank line</span><span class="pun">.</span><span class="pln"></span><span class="typ" style="color: rgb(68, 85, 136);">This</span><span class="pln"> line </span><span class="kwd">is</span><span class="pln"> followed </span><span class="kwd">by</span><span class="pln"> </span><span class="lit" style="color: rgb(68, 85, 136);">2</span><span class="pln"> blank lines</span><span class="pun">.</span><span class="pln"></span><span class="typ" style="color: rgb(68, 85, 136);">This</span><span class="pln"> line </span><span class="kwd">is</span><span class="pln"> followed </span><span class="kwd">by</span><span class="pln"> </span><span class="lit" style="color: rgb(68, 85, 136);">3</span><span class="pln"> blank lines</span><span class="pun">.</span><span class="pln"></span><span class="typ" style="color: rgb(68, 85, 136);">This</span><span class="pln"> line </span><span class="kwd">is</span><span class="pln"> followed </span><span class="kwd">by</span><span class="pln"> </span><span class="lit" style="color: rgb(68, 85, 136);">4</span><span class="pln"> blank lines</span><span class="pun">.</span><span class="pln"></span><span class="typ" style="color: rgb(68, 85, 136);">This</span><span class="pln"> </span><span class="kwd">is</span><span class="pln"> the </span><span class="kwd">end</span><span class="pun">.</span>

    D命令只会删除模式空间的第一行,而且删除后会重新在模式空间的内容上执行编辑命令,类似形成一个循环,前提是相连的都是空行。当匹配一个空行时,N读取下一行内容,此时匹配^\n$导致模式空间中的第一行被删除。现在模式空间中的内容是空的,重新执行编辑命令,此时匹配/^$/。继续读取下一行,当下一行依然为空行时,重复之前的动作,否则输出当前模式空间的内容。造成的结果是连续多个空行,只有最后一个空行是保留输出的,其余的都被删除了。这样的结果才是我们最初希望得到的。

    打印行:P

    P命令与p命令一样是打印模式空间的内容,不同的是前者仅打印模式空间的第一行内容,而后者是打印所有的内容。因为编辑命令全部执行完之后,sed默认会输出模式空间的内容,所以一般情况下,p和P命令都是与-n选项一起使用的。但是有一种情况是例外的,即编辑命令的执行流程被改变的情况,例如N,D等。很多情况下,P命令都是用在N命令之后,D命令之前的。这三个命令合起来,可以形成一人输入输出的循环,并且每次只打印一行:读入一行后,N继续读下一行,P命令打印第一行,D命令删除第一行,执行流程回到最开始重复该过程。

    <span class="pln">$ echo </span><span class="pun">-</span><span class="pln">e </span><span class="str" style="color: rgb(221, 17, 68);">"line1\nline2\nline3"</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> sed </span><span class="str" style="color: rgb(221, 17, 68);">'$!N;P;D'</span>

    不过多行命令用起来要格外小心,你要用自己的大脑去演算一遍执行的过程,要不然很容易出错,比如:

    <span class="pln">$ echo </span><span class="pun">-</span><span class="pln">e </span><span class="str" style="color: rgb(221, 17, 68);">"line1\nline2\nline3"</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> sed </span><span class="pun">-</span><span class="pln">n </span><span class="str" style="color: rgb(221, 17, 68);">'N;1P'</span>

    你可能期望打印第一行的内容,事实上并没有输出。原因是当N继续读入第二行后,当前行号已经是2了,我们在第二篇笔记中曾经说过,行号只是sed在内部维护的一个计数变量而已,每当读入新的一行,行号就加一:

    <span class="pln">$ echo </span><span class="pun">-</span><span class="pln">e </span><span class="str" style="color: rgb(221, 17, 68);">"line1\nline2\nline3"</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> sed </span><span class="pun">-</span><span class="pln">n </span><span class="str" style="color: rgb(221, 17, 68);">'$!N;='</span><span class="pln"></span><span class="lit" style="color: rgb(68, 85, 136);">2</span><span class="pln"></span><span class="lit" style="color: rgb(68, 85, 136);">3</span>

    我们依然用替换Unix System为Unix Operating System作为例子,介绍N/P/D三个命令是如何配合使用的。

    示例文本如下所示,为了举例方便,这段文本仅有三行内容,刚好可以演示一个循环的处理过程:

    <span class="pln">$ cat text</span><span class="typ" style="color: rgb(68, 85, 136);">The</span><span class="pln"> UNIX</span><span class="typ" style="color: rgb(68, 85, 136);">System</span><span class="pln"> </span><span class="kwd">and</span><span class="pln"> UNIX</span><span class="pun">...</span>

    执行的命令:

    <span class="pln">$ sed </span><span class="str" style="color: rgb(221, 17, 68);">'/UNIX$/{> N> s/\nSystem/ Operating &/> P> D> }'</span><span class="pln"> text</span><span class="typ" style="color: rgb(68, 85, 136);">The</span><span class="pln"> UNIX </span><span class="typ" style="color: rgb(68, 85, 136);">Operating</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">System</span><span class="pln"> </span><span class="kwd">and</span><span class="pln"> UNIX</span><span class="pun">...</span>

    执行过程如下图所示:
    NDP Loop

    以上三个命令的用法与之前介绍的基础命令是截然不同的,有些同学可能都没有接触过。在下一篇中,我会介绍更多高级的命令,同时为引入一个新的概念:保持空间(Hold Space)。

    保持空间

    保持空间用于保存模式空间的内容,模式空间的内容可以复制到保持空间,同样地保持空间的内容可以复制回模式空间。sed提供了几组命令用来完成复制的工作,其它命令无法匹配也不能修改模式空间的内容。

    操作保持空间的命令如下所示:

    名称命令说明保存(Hold)h/H将模式空间的内容复制或者追加到保持空间取回(Get)g/G将保持空间的内容复制或者追加到模式空间交换(Exchange)x交换模式空间和保持空间的内容

    这几组命令提供了保存、取回以及交换三个动作,交换命令比较容易理解,保存命令和取回命令都有大写和小写两种形式,这两种形式的区别是小写的是将会覆盖目的空间的内容,而大写的是将内容追加到目的空间,追加的内容和原有的内容是以\n分隔。

    基本使用

    我们随便试试这几个命令,假设有如下测试文本:

    <span class="pln">$ cat text</span><span class="lit" style="color: rgb(68, 85, 136);">1</span><span class="pln"></span><span class="lit" style="color: rgb(68, 85, 136);">2</span><span class="pln"></span><span class="lit" style="color: rgb(68, 85, 136);">11</span><span class="pln"></span><span class="lit" style="color: rgb(68, 85, 136);">22</span><span class="pln"></span><span class="lit" style="color: rgb(68, 85, 136);">111</span><span class="pln"></span><span class="lit" style="color: rgb(68, 85, 136);">222</span>

    1. 首先,仅使用h/H或者g/G命令:

    使用h命令:

    <span class="pln">$ sed </span><span class="str" style="color: rgb(221, 17, 68);">'h'</span><span class="pln"> text</span><span class="lit" style="color: rgb(68, 85, 136);">1</span><span class="pln"></span><span class="lit" style="color: rgb(68, 85, 136);">2</span><span class="pln"></span><span class="lit" style="color: rgb(68, 85, 136);">11</span><span class="pln"></span><span class="lit" style="color: rgb(68, 85, 136);">22</span><span class="pln"></span><span class="lit" style="color: rgb(68, 85, 136);">111</span><span class="pln"></span><span class="lit" style="color: rgb(68, 85, 136);">222</span>

    使用G命令:

    <span class="pln">$ sed </span><span class="str" style="color: rgb(221, 17, 68);">'G'</span><span class="pln"> text</span><span class="lit" style="color: rgb(68, 85, 136);">1</span><span class="pln"></span><span class="lit" style="color: rgb(68, 85, 136);">2</span><span class="pln"></span><span class="lit" style="color: rgb(68, 85, 136);">11</span><span class="pln"></span><span class="lit" style="color: rgb(68, 85, 136);">22</span><span class="pln"></span><span class="lit" style="color: rgb(68, 85, 136);">111</span><span class="pln"></span><span class="lit" style="color: rgb(68, 85, 136);">222</span>

    前者返回的结果正常,因为复制到保持空间的内容并没有取回;后者每一行的后面都多了一个空行,原因是每行都会从保持空间取回一行,追加(大写的G)到模式空间的内容之后,以\n分隔。

    2. 使用x命令交换空间

    <span class="pln">$ sed </span><span class="str" style="color: rgb(221, 17, 68);">'x'</span><span class="pln"> text</span><span class="lit" style="color: rgb(68, 85, 136);">1</span><span class="pln"></span><span class="lit" style="color: rgb(68, 85, 136);">2</span><span class="pln"></span><span class="lit" style="color: rgb(68, 85, 136);">11</span><span class="pln"></span><span class="lit" style="color: rgb(68, 85, 136);">22</span><span class="pln"></span><span class="lit" style="color: rgb(68, 85, 136);">111</span>

    命令执行后,发现前面多了一个空行并且最后一行不见了。我在前面一直强调sed命令用好,要有用大脑回顾命令执行过程的能力:

    * 当读入第一行的时候,模式空间中的内容是第一行的内容,而保持空间是空的,这个时候交换两个空间,导致模式空间为空,保持空间为第一行的内容,因此输出为空行;
    * 当读入下一行之后,模式空间为第2行的内容,保持空间为第一行的内容,交换后输出第1行的内容;
    * 依次读入每一行,输出上一行的内容;
    * 直到最后一行被读入到模式空间,交换后输出倒数第二行的内容,而最后一行的内容并没有输出,此时命令执行结束。

    深入使用

    上面的例子简单地介绍了保持空间命令的基本使用方法,这些命令单个使用可能效果不大,但是组合起来的效果是非常好的。

    1.第一个例子: 使用逗号拼接行

    <span class="pln">$ sed </span><span class="str" style="color: rgb(221, 17, 68);">'H;$!d;${x;s/^\n//;s/\n/,/g}'</span><span class="pln"> text</span><span class="lit" style="color: rgb(68, 85, 136);">1</span><span class="pun">,</span><span class="lit" style="color: rgb(68, 85, 136);">11</span><span class="pun">,</span><span class="lit" style="color: rgb(68, 85, 136);">2</span><span class="pun">,</span><span class="lit" style="color: rgb(68, 85, 136);">11</span><span class="pun">,</span><span class="lit" style="color: rgb(68, 85, 136);">22</span><span class="pun">,</span><span class="lit" style="color: rgb(68, 85, 136);">111</span><span class="pun">,</span><span class="lit" style="color: rgb(68, 85, 136);">222</span>

    上面的命令执行过程是这样的,使用H将每一行都追加到保持空间,这里利用d命令打断常规的命令执行流程,让sed继续读入新的一行,直接到将最后一行都放到保持空间。这个时候使用x命令将保持空间的内容交换到模式空间,模式空间的内容现在是这样的:\n1\n11\n2\n11\n22\n111\n222。替换的步骤分成两个,首先去掉首个回车符,然后把剩余的回车符替换成逗号。

    其实上面的过程可以包装成一个常用的函数:

    <span class="pln">$ </span><span class="kwd">function</span><span class="pln"> join_lines</span><span class="pun">()</span><span class="pln"></span><span class="pun">></span><span class="pln"> </span><span class="pun">{</span><span class="pln"></span><span class="pun">></span><span class="pln">    sed </span><span class="str" style="color: rgb(221, 17, 68);">'H;$!d;${x;s/^\n//;s/\n/,/g}'</span><span class="pln"> $1</span><span class="pun">></span><span class="pln"> </span><span class="pun">}</span><span class="pln">$ join_lines text</span><span class="lit" style="color: rgb(68, 85, 136);">1</span><span class="pun">,</span><span class="lit" style="color: rgb(68, 85, 136);">11</span><span class="pun">,</span><span class="lit" style="color: rgb(68, 85, 136);">2</span><span class="pun">,</span><span class="lit" style="color: rgb(68, 85, 136);">11</span><span class="pun">,</span><span class="lit" style="color: rgb(68, 85, 136);">22</span><span class="pun">,</span><span class="lit" style="color: rgb(68, 85, 136);">111</span><span class="pun">,</span><span class="lit" style="color: rgb(68, 85, 136);">222</span>

    进一步,我们可以让分隔符可以通过参数设置,另外一方面删除文件名的参数,而改成常见的过滤器命令形式(即通过管道传递输入):

    <span class="pln">$ </span><span class="kwd">function</span><span class="pln"> join_lines</span><span class="pun">()</span><span class="pln"></span><span class="pun">></span><span class="pln"> </span><span class="pun">{</span><span class="pln"></span><span class="pun">></span><span class="pln">     </span><span class="kwd">local</span><span class="pln"> delim</span><span class="pun">=</span><span class="pln">$</span><span class="pun">{</span><span class="lit" style="color: rgb(68, 85, 136);">1</span><span class="pun">:-,}</span><span class="pln"></span><span class="pun">></span><span class="pln">     sed </span><span class="str" style="color: rgb(221, 17, 68);">'H;$!d;${x;s/^\n//;s/\n/'</span><span class="pln">$delim</span><span class="str" style="color: rgb(221, 17, 68);">'/g}'</span><span class="pln"></span><span class="pun">></span><span class="pln"> </span><span class="pun">}</span><span class="pln">$ cat text </span><span class="pun">|</span><span class="pln"> join_lines </span><span class="str" style="color: rgb(221, 17, 68);">';'</span><span class="pln"></span><span class="lit" style="color: rgb(68, 85, 136);">1</span><span class="pun">;</span><span class="lit" style="color: rgb(68, 85, 136);">11</span><span class="pun">;</span><span class="lit" style="color: rgb(68, 85, 136);">2</span><span class="pun">;</span><span class="lit" style="color: rgb(68, 85, 136);">11</span><span class="pun">;</span><span class="lit" style="color: rgb(68, 85, 136);">22</span><span class="pun">;</span><span class="lit" style="color: rgb(68, 85, 136);">111</span><span class="pun">;</span><span class="lit" style="color: rgb(68, 85, 136);">222</span>

    但是如果我们要用&作为符号,就会出现问题:

    <span class="pln">$ cat text </span><span class="pun">|</span><span class="pln"> join_lines </span><span class="str" style="color: rgb(221, 17, 68);">'&'</span><span class="pln"></span><span class="lit" style="color: rgb(68, 85, 136);">1</span><span class="pln"></span><span class="lit" style="color: rgb(68, 85, 136);">11</span><span class="pln"></span><span class="lit" style="color: rgb(68, 85, 136);">2</span><span class="pln"></span><span class="lit" style="color: rgb(68, 85, 136);">11</span><span class="pln"></span><span class="lit" style="color: rgb(68, 85, 136);">22</span><span class="pln"></span><span class="lit" style="color: rgb(68, 85, 136);">111</span><span class="pln"></span><span class="lit" style="color: rgb(68, 85, 136);">222</span>

    上面并没有&作为分隔符,这是因为&是元字符,表示匹配的部分,这里刚好是回车符\n。因此我们需要对分隔符进行转义:

    <span class="pln">$ </span><span class="kwd">function</span><span class="pln"> join_lines</span><span class="pun">()</span><span class="pln"></span><span class="pun">></span><span class="pln"> </span><span class="pun">{</span><span class="pln"></span><span class="pun">></span><span class="pln">      </span><span class="kwd">local</span><span class="pln"> delim</span><span class="pun">=</span><span class="pln">$</span><span class="pun">{</span><span class="lit" style="color: rgb(68, 85, 136);">1</span><span class="pun">:-,}</span><span class="pln"></span><span class="pun">></span><span class="pln">      sed </span><span class="str" style="color: rgb(221, 17, 68);">'H;$!d;${x;s/^\n//;s/\n/\'$delim'</span><span class="pun">/</span><span class="pln">g</span><span class="pun">}</span><span class="str" style="color: rgb(221, 17, 68);">'> } $ cat text | join_lines '</span><span class="pun">&</span><span class="str" style="color: rgb(221, 17, 68);">'1&11&2&11&22&111&222</span>

    2.第二个例子:将语句中的特定单词转换成大写

    现在有这样的文本,有许多类似这样的find the Match statement语句,其中Match是语句的名称,但是这个单词的大小写不统一,有些地方是小写的,有些地方是首字符大写,现在我们要做的是把这个单词统一转换成大写。

    容易联想到的是Sed&awk笔记之sed篇:基础命令中介绍的y命令,利用y命令确实可以做到小写转换成大写,转换的命令是这样的:

    <span class="pln">y</span><span class="pun">/</span><span class="pln">abcdefghijklmnopqrstuvwxyz</span><span class="pun">/</span><span class="pln">ABCDEFGHIJKLMNOPQRSTUVWXYZ</span><span class="pun">/</span>

    但是y命令是会把模式空间的所有内容都转换,这样不能满足我们的需求。但是我们可以利用保持空间保存当前行,然后处理模式空间中的内容:

    <span class="str" style="color: rgb(221, 17, 68);">/the .* statement/</span><span class="pun">{</span><span class="pln">hs</span><span class="pun">/.*</span><span class="pln">the \(</span><span class="pun">.*</span><span class="pln">\) statement</span><span class="pun">.*/</span><span class="pln">\1</span><span class="pun">/</span><span class="pln">y</span><span class="pun">/</span><span class="pln">abcdefghijklmnopqrstuvwxyz</span><span class="pun">/</span><span class="pln">ABCDEFGHIJKLMNOPQRSTUVWXYZ</span><span class="pun">/</span><span class="pln">Gs</span><span class="pun">/</span><span class="pln">\(</span><span class="pun">.*</span><span class="pln">\)\n\(</span><span class="pun">.*</span><span class="pln">the \)</span><span class="pun">.*</span><span class="pln">\( statement</span><span class="pun">.*</span><span class="pln">\)</span><span class="pun">/</span><span class="pln">\2\1\3</span><span class="pun">/</span><span class="pln"></span><span class="pun">}</span>

    老规矩一条一条过上面的命令,为了方便说明,每个命令解释后我都会给出当前模式空间和保持空间的内容。

    首先找到需要处理的行(假设当前行为find the Match statement)。

    Pattern space: find the Match statement

    将当前行保存到保持空间:

    Pattern space: find the Match statementHold space: find the Match statement

    然后利用替换命令获取需要处理的单词:

    Pattern space: MatchHold space: find the Match statement

    然后通过转换命令将其转换成大写:

    Pattern space: MATCHHold space: find the Match statement

    现在再利用G命令将保持空间的内容追加到模式空间最后:

    Pattern space: MATCH\nfind the Match statementHold space: find the Match statement

    最后再次利用替换命令处理下:

    Pattern space: find the MATCH statementHold space: find the Match statement

    流程控制

    一般情况下,sed是将编辑命令从上到下依次应用到读入的行上,但是像d/n/D/N命令都能够在一定程度上改变默认的执行流程,甚至利用N/D/P三个命令可以形成一个强大的循环处理流程。除此之外,其实sed还提供了分支命令(b)和测试(test)两个命令来控制流程,这两个命令可以跳转到指定的标签(label)位置继续执行命令。标签是以冒号开头的标记,如下例中的:top标签:

    <span class="pun">:</span><span class="pln">topcommand1command2</span><span class="pun">/</span><span class="pln">pattern</span><span class="pun">/</span><span class="pln">b topcommand3</span>

    当执行到/pattern/b top时,如果匹配pattern,则跳转到:top标签所在的位置,继续执行下一个命令command1。

    如果没有指定标签,则将控制转移到脚本的结尾处。也许这只是一个默认的行为,但是有时候如果用得好也是非常有用的,例如:

    <span class="str" style="color: rgb(221, 17, 68);">/pattern/</span><span class="pln">bcommand </span><span class="lit" style="color: rgb(68, 85, 136);">1</span><span class="pln">command </span><span class="lit" style="color: rgb(68, 85, 136);">2</span><span class="pln">command </span><span class="lit" style="color: rgb(68, 85, 136);">3</span>

    当执行到/pattern/b时,如果匹配pattern,则跳转到最后。这种情况下匹配pattern的行可以避开执行后续的命令,被排除在外。

    下一个例子中,我们利用分支命令的跳转效果达到类似if语句的效果:

    <span class="pln">command1</span><span class="pun">/</span><span class="pln">pattern</span><span class="pun">/</span><span class="pln">b </span><span class="kwd">end</span><span class="pln">command2</span><span class="pun">:</span><span class="kwd">end</span><span class="pln">command3</span>

    当执行到/pattern/b end时,如果匹配pattern,则跳转到:end标签所在的位置,跳过command2而不执行。

    进一步地,利用两个分支命令可以达到if..else的分支效果:

    <span class="pln">command1</span><span class="pun">/</span><span class="pln">pattern</span><span class="pun">/</span><span class="pln">b dothreecommand2b</span><span class="pun">:</span><span class="pln">dothreecommand3</span>

    这个例子中,当执行到/pattern/b dothree时,若匹配pattern则中转到:dothree标签,此时执行command3;若不匹配,则执行command2,并且跳转到最后。

    上面的例子都是用到了分支命令,分支命令的跳转是无条件的。而与之相对的是测试命令,测试命令的跳转是有条件的,当且仅当当前行发生成功的替换时才跳转。

    为了说明测试命令的用法,我们用它来实现前文定义过的join_lines函数:

    <span class="pln">$ sed </span><span class="str" style="color: rgb(221, 17, 68);">':a;$!N;s/\n/,/;ta'</span><span class="pln"> text</span><span class="lit" style="color: rgb(68, 85, 136);">1</span><span class="pun">,</span><span class="lit" style="color: rgb(68, 85, 136);">11</span><span class="pun">,</span><span class="lit" style="color: rgb(68, 85, 136);">2</span><span class="pun">,</span><span class="lit" style="color: rgb(68, 85, 136);">11</span><span class="pun">,</span><span class="lit" style="color: rgb(68, 85, 136);">22</span><span class="pun">,</span><span class="lit" style="color: rgb(68, 85, 136);">111</span><span class="pun">,</span><span class="lit" style="color: rgb(68, 85, 136);">222</span>

    在最前面我们添加了一个标签:a,然后在再最后面利用测试命令跳转到该标签。可能,你会觉得这里也可以用分支命令,但是事实上分支命令会导致死循环,因为在它里他没有结束的条件。

    但是测试命令就不同了,这一点直到最后才体现出来。当最后一行被N命令读入之后,回车替换成逗号,此时ta继续跳转到最开头,因为所有行都已经被读入,所以$!不匹配,同时模式空间中的回车已经全部被替换成逗号,所以替换也不会发生。之前我们说过,当且仅当当前行发生成功的替换时测试命令才跳转。所以此时跳转不会发生,退出sed命令。

    我们可以利用sedsed这个工具来验证上面的过程,sedsed可以用来调试sed脚本。

    <span class="pln">$ </span><span class="pun">./</span><span class="pln">sedsed </span><span class="pun">-</span><span class="pln">d </span><span class="pun">-</span><span class="pln">e </span><span class="str" style="color: rgb(221, 17, 68);">':a;$!N;s/\n/,/;ta'</span><span class="pln"> textPATT</span><span class="pun">:</span><span class="lit" style="color: rgb(68, 85, 136);">1</span><span class="pln">$HOLD</span><span class="pun">:</span><span class="pln">$COMM</span><span class="pun">::</span><span class="pln">aCOMM</span><span class="pun">:</span><span class="pln">$ </span><span class="pun">!</span><span class="pln">NPATT</span><span class="pun">:</span><span class="lit" style="color: rgb(68, 85, 136);">1</span><span class="pln">\n</span><span class="lit" style="color: rgb(68, 85, 136);">11</span><span class="pln">$HOLD</span><span class="pun">:</span><span class="pln">$COMM</span><span class="pun">:</span><span class="pln">s</span><span class="pun">/</span><span class="pln">\n</span><span class="pun">/,/</span><span class="pln">PATT</span><span class="pun">:</span><span class="lit" style="color: rgb(68, 85, 136);">1</span><span class="pun">,</span><span class="lit" style="color: rgb(68, 85, 136);">11</span><span class="pln">$HOLD</span><span class="pun">:</span><span class="pln">$COMM</span><span class="pun">:</span><span class="pln">t aCOMM</span><span class="pun">:</span><span class="pln">$ </span><span class="pun">!</span><span class="pln">NPATT</span><span class="pun">:</span><span class="lit" style="color: rgb(68, 85, 136);">1</span><span class="pun">,</span><span class="lit" style="color: rgb(68, 85, 136);">11</span><span class="pln">\n</span><span class="lit" style="color: rgb(68, 85, 136);">2</span><span class="pln">$HOLD</span><span class="pun">:</span><span class="pln">$</span><span class="pun">...</span><span class="pln"></span><span class="pun">...</span><span class="pln">COMM</span><span class="pun">:</span><span class="pln">$ </span><span class="pun">!</span><span class="pln">NPATT</span><span class="pun">:</span><span class="lit" style="color: rgb(68, 85, 136);">1</span><span class="pun">,</span><span class="lit" style="color: rgb(68, 85, 136);">11</span><span class="pun">,</span><span class="lit" style="color: rgb(68, 85, 136);">2</span><span class="pun">,</span><span class="lit" style="color: rgb(68, 85, 136);">11</span><span class="pun">,</span><span class="lit" style="color: rgb(68, 85, 136);">22</span><span class="pun">,</span><span class="lit" style="color: rgb(68, 85, 136);">111</span><span class="pun">,</span><span class="lit" style="color: rgb(68, 85, 136);">222</span><span class="pln">\n</span><span class="lit" style="color: rgb(68, 85, 136);">1111</span><span class="pln">$HOLD</span><span class="pun">:</span><span class="pln">$COMM</span><span class="pun">:</span><span class="pln">s</span><span class="pun">/</span><span class="pln">\n</span><span class="pun">/,/</span><span class="pln">PATT</span><span class="pun">:</span><span class="lit" style="color: rgb(68, 85, 136);">1</span><span class="pun">,</span><span class="lit" style="color: rgb(68, 85, 136);">11</span><span class="pun">,</span><span class="lit" style="color: rgb(68, 85, 136);">2</span><span class="pun">,</span><span class="lit" style="color: rgb(68, 85, 136);">11</span><span class="pun">,</span><span class="lit" style="color: rgb(68, 85, 136);">22</span><span class="pun">,</span><span class="lit" style="color: rgb(68, 85, 136);">111</span><span class="pun">,</span><span class="lit" style="color: rgb(68, 85, 136);">222</span><span class="pun">,</span><span class="lit" style="color: rgb(68, 85, 136);">1111</span><span class="pln">$HOLD</span><span class="pun">:</span><span class="pln">$COMM</span><span class="pun">:</span><span class="pln">t aCOMM</span><span class="pun">:</span><span class="pln">$ </span><span class="pun">!</span><span class="pln">NPATT</span><span class="pun">:</span><span class="lit" style="color: rgb(68, 85, 136);">1</span><span class="pun">,</span><span class="lit" style="color: rgb(68, 85, 136);">11</span><span class="pun">,</span><span class="lit" style="color: rgb(68, 85, 136);">2</span><span class="pun">,</span><span class="lit" style="color: rgb(68, 85, 136);">11</span><span class="pun">,</span><span class="lit" style="color: rgb(68, 85, 136);">22</span><span class="pun">,</span><span class="lit" style="color: rgb(68, 85, 136);">111</span><span class="pun">,</span><span class="lit" style="color: rgb(68, 85, 136);">222</span><span class="pun">,</span><span class="lit" style="color: rgb(68, 85, 136);">1111</span><span class="pln">$HOLD</span><span class="pun">:</span><span class="pln">$COMM</span><span class="pun">:</span><span class="pln">s</span><span class="pun">/</span><span class="pln">\n</span><span class="pun">/,/</span><span class="pln">PATT</span><span class="pun">:</span><span class="lit" style="color: rgb(68, 85, 136);">1</span><span class="pun">,</span><span class="lit" style="color: rgb(68, 85, 136);">11</span><span class="pun">,</span><span class="lit" style="color: rgb(68, 85, 136);">2</span><span class="pun">,</span><span class="lit" style="color: rgb(68, 85, 136);">11</span><span class="pun">,</span><span class="lit" style="color: rgb(68, 85, 136);">22</span><span class="pun">,</span><span class="lit" style="color: rgb(68, 85, 136);">111</span><span class="pun">,</span><span class="lit" style="color: rgb(68, 85, 136);">222</span><span class="pun">,</span><span class="lit" style="color: rgb(68, 85, 136);">1111</span><span class="pln">$HOLD</span><span class="pun">:</span><span class="pln">$COMM</span><span class="pun">:</span><span class="pln">t aPATT</span><span class="pun">:</span><span class="lit" style="color: rgb(68, 85, 136);">1</span><span class="pun">,</span><span class="lit" style="color: rgb(68, 85, 136);">11</span><span class="pun">,</span><span class="lit" style="color: rgb(68, 85, 136);">2</span><span class="pun">,</span><span class="lit" style="color: rgb(68, 85, 136);">11</span><span class="pun">,</span><span class="lit" style="color: rgb(68, 85, 136);">22</span><span class="pun">,</span><span class="lit" style="color: rgb(68, 85, 136);">111</span><span class="pun">,</span><span class="lit" style="color: rgb(68, 85, 136);">222</span><span class="pun">,</span><span class="lit" style="color: rgb(68, 85, 136);">1111</span><span class="pln">$HOLD</span><span class="pun">:</span><span class="pln">$</span><span class="lit" style="color: rgb(68, 85, 136);">1</span><span class="pun">,</span><span class="lit" style="color: rgb(68, 85, 136);">11</span><span class="pun">,</span><span class="lit" style="color: rgb(68, 85, 136);">2</span><span class="pun">,</span><span class="lit" style="color: rgb(68, 85, 136);">11</span><span class="pun">,</span><span class="lit" style="color: rgb(68, 85, 136);">22</span><span class="pun">,</span><span class="lit" style="color: rgb(68, 85, 136);">111</span><span class="pun">,</span><span class="lit" style="color: rgb(68, 85, 136);">222</span><span class="pun">,</span><span class="lit" style="color: rgb(68, 85, 136);">1111</span>

    看第27行替换命令发生的时候,此时模式空间的内容为PATT:1,11,2,11,22,111,222,1111$,因此替换失败,ta命令不会发生跳转,脚本执行退出。

    而如果在这里把测试命令换成分支命令,整个执行过程就会陷入死循环了:

    <span class="pln">COMM</span><span class="pun">:</span><span class="pln">b aCOMM</span><span class="pun">:</span><span class="pln">$ </span><span class="pun">!</span><span class="pln">NPATT</span><span class="pun">:</span><span class="lit" style="color: rgb(68, 85, 136);">1</span><span class="pun">,</span><span class="lit" style="color: rgb(68, 85, 136);">11</span><span class="pun">,</span><span class="lit" style="color: rgb(68, 85, 136);">2</span><span class="pun">,</span><span class="lit" style="color: rgb(68, 85, 136);">11</span><span class="pun">,</span><span class="lit" style="color: rgb(68, 85, 136);">22</span><span class="pun">,</span><span class="lit" style="color: rgb(68, 85, 136);">111</span><span class="pun">,</span><span class="lit" style="color: rgb(68, 85, 136);">222</span><span class="pun">,</span><span class="lit" style="color: rgb(68, 85, 136);">1111</span><span class="pln">$HOLD</span><span class="pun">:</span><span class="pln">$COMM</span><span class="pun">:</span><span class="pln">s</span><span class="pun">/</span><span class="pln">\n</span><span class="pun">/,/</span><span class="pln">PATT</span><span class="pun">:</span><span class="lit" style="color: rgb(68, 85, 136);">1</span><span class="pun">,</span><span class="lit" style="color: rgb(68, 85, 136);">11</span><span class="pun">,</span><span class="lit" style="color: rgb(68, 85, 136);">2</span><span class="pun">,</span><span class="lit" style="color: rgb(68, 85, 136);">11</span><span class="pun">,</span><span class="lit" style="color: rgb(68, 85, 136);">22</span><span class="pun">,</span><span class="lit" style="color: rgb(68, 85, 136);">111</span><span class="pun">,</span><span class="lit" style="color: rgb(68, 85, 136);">222</span><span class="pun">,</span><span class="lit" style="color: rgb(68, 85, 136);">1111</span><span class="pln">$HOLD</span><span class="pun">:</span><span class="pln">$COMM</span><span class="pun">:</span><span class="pln">b aCOMM</span><span class="pun">:</span><span class="pln">$ </span><span class="pun">!</span><span class="pln">NPATT</span><span class="pun">:</span><span class="lit" style="color: rgb(68, 85, 136);">1</span><span class="pun">,</span><span class="lit" style="color: rgb(68, 85, 136);">11</span><span class="pun">,</span><span class="lit" style="color: rgb(68, 85, 136);">2</span><span class="pun">,</span><span class="lit" style="color: rgb(68, 85, 136);">11</span><span class="pun">,</span><span class="lit" style="color: rgb(68, 85, 136);">22</span><span class="pun">,</span><span class="lit" style="color: rgb(68, 85, 136);">111</span><span class="pun">,</span><span class="lit" style="color: rgb(68, 85, 136);">222</span><span class="pun">,</span><span class="lit" style="color: rgb(68, 85, 136);">1111</span><span class="pln">$</span>

    高级命令总结

    到此为止,所有高级命令的用法就已经介绍完了。最后一段内容由于时间的关系,写得比较仓促。高级命令的用法比起基础命令相对复杂一点,而且容易出错,需要十分小心,如果不确定可以用上面介绍的sedsed工具来调式下,而且便于加深各种命令行为的理解。

    相信大家肯定用过grep这个命令,它可以找出匹配某个正则表达式的行,例如查看包含"the word"的行:

    <span class="pln">$ grep </span><span class="str" style="color: rgb(221, 17, 68);">"the word"</span><span class="pln"> filename</span>

    但是grep是针对单行作匹配的,所以如果一个短句跨越了两行就无法匹配。这就给我们出了一个题目,如何用sed模仿grep的行为,并且支持跨行短句的匹配呢?

    当单词仅出现在一行时很简单,用普通的正则就可以匹配,这里我们用到分支命令,当匹配时则跳转到最后:

    /the word/b

    当单词跨越两行,容易想到用N命令将下一行读取到模式空间再做处理。例如我们同样要查找短句"the word",现在的文本是这样的:

    <span class="pln">$ cat textwe want to find the phrase theword</span><span class="pun">,</span><span class="pln"> but it appears across two lines</span><span class="pun">.</span>

    当用N玲读入下一行时,模式空间的内容如下所示:

    Pattern space: we want to find the phrase the\nword, but it appears across two lines.

    因此,需要将回车符号删除,然后再作匹配。

    $!Ns/ *\n/ //the word/b

    可是这里会有一个问题,如果短句恰好在读入的第二行的话,虽然匹配,但是会打印出模式空间中的所有内容,这样不符合grep的行为,只显示包含短句的那一行。所以这里要再加一个处理,将模式空间的第一行内容删除,再在第二行中匹配。但是在此之前,首先要保存模式空间的内容,否则可没有后悔药可吃。

    h命令可以将模式空间的内容保存到保持空间,然后利用替换命令将模式空间的第一行内容清除,然后再作匹配处理:

    $!Nhs/.*\n///the word/b

    如果不匹配,则短句可能确实是跨越两行,这时候我们首先用g命令将之前保存的内容从保持空间取回到模式空间,替换掉回车后再进行匹配:

    gs/ *\n/ //the word/b

    这里如果匹配则直接跳转到最后,并且输出的内容是替换后的内容。

    但是我们要输出的是匹配的原文,而原文现在在保持空间还有一份拷贝,因此当匹配时,需要将原文从保持空间取回:

    gs/ *\n/ //the word/{gb}

    同样地,我们要考虑不匹配的情况,不匹配的时候也要将会原文从保持空间取回,并且将模式空间的第一行删除,继续处理下一行:

    gs/ *\n/ //the word/{gb}gD

    将所有的sed脚本合在一起,假设我们将以下内容保存到phrase.sed文件中:

    /the word/b$!Nhs/.*\n///the word/bgs/ *\n///the word/{gb}gD

    接下来,我们用一段文本来测试下以上的脚本是否正确:

    <span class="pln">$ cat text</span><span class="typ" style="color: rgb(68, 85, 136);">We</span><span class="pln"> will </span><span class="kwd">use</span><span class="pln"> phrase</span><span class="pun">.</span><span class="pln">sed to </span><span class="kwd">print</span><span class="pln"> any line which containsthe word</span><span class="pun">.</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Or</span><span class="pln"> </span><span class="kwd">if</span><span class="pln"> the word appears across two lines</span><span class="pun">,</span><span class="pln"> likebelow</span><span class="pun">:</span><span class="pln"></span><span class="typ" style="color: rgb(68, 85, 136);">It</span><span class="pln"> will </span><span class="kwd">print</span><span class="pln"> </span><span class="kwd">this</span><span class="pln"> line</span><span class="pun">,</span><span class="pln"> because theword appears across two lines</span><span class="pun">.</span><span class="pln"></span><span class="typ" style="color: rgb(68, 85, 136);">You</span><span class="pln"> can run sed </span><span class="pun">-</span><span class="pln">f phrase</span><span class="pun">.</span><span class="pln">sed text to test </span><span class="kwd">this</span><span class="pun">.</span>

    执行命令如下所示:

    <span class="pln">$ sed </span><span class="pun">-</span><span class="pln">f phrase</span><span class="pun">.</span><span class="pln">sed textthe word</span><span class="pun">.</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Or</span><span class="pln"> </span><span class="kwd">if</span><span class="pln"> the word appears across two lines</span><span class="pun">,</span><span class="pln"> like</span><span class="typ" style="color: rgb(68, 85, 136);">It</span><span class="pln"> will </span><span class="kwd">print</span><span class="pln"> </span><span class="kwd">this</span><span class="pln"> line</span><span class="pun">,</span><span class="pln"> because theword appears across two lines</span><span class="pun">.</span>

    上面的命令中的"the word"其实可以是一个变量,这样我们就可以将这个功能写成一个脚本或者函数,用在更多地方:

    <span class="pln">$ cat phrase</span><span class="pun">.</span><span class="pln">sh </span><span class="com" style="color: rgb(153, 153, 136);">#! /bin/sh</span><span class="pln"></span><span class="com" style="color: rgb(153, 153, 136);"># phrase -- search for words across lines</span><span class="pln"></span><span class="com" style="color: rgb(153, 153, 136);"># $1 = search string; remaining args = filenames</span><span class="pln">search</span><span class="pun">=</span><span class="pln">$1</span><span class="kwd">for</span><span class="pln"> file </span><span class="kwd">in</span><span class="pln"> $</span><span class="pun">{@:</span><span class="lit" style="color: rgb(68, 85, 136);">2</span><span class="pun">};</span><span class="pln"> </span><span class="kwd">do</span><span class="pln">    sed </span><span class="str" style="color: rgb(221, 17, 68);">"/$search/b    \$!N    h    s/.*\n//    /$search/b    g    s/ *\n/ /    /$search/{    g    b    }    g    D"</span><span class="pln"> $file</span><span class="kwd">done</span><span class="pln">$ chmod </span><span class="pun">+</span><span class="pln">x phrase</span><span class="pun">.</span><span class="pln">sh$ </span><span class="pun">./</span><span class="pln">phrase</span><span class="pun">.</span><span class="pln">sh </span><span class="str" style="color: rgb(221, 17, 68);">'the word'</span><span class="pln"> textthe word</span><span class="pun">.</span><span class="pln"> </span><span class="typ" style="color: rgb(68, 85, 136);">Or</span><span class="pln"> </span><span class="kwd">if</span><span class="pln"> the word appears across two lines</span><span class="pun">,</span><span class="pln"> like</span><span class="typ" style="color: rgb(68, 85, 136);">It</span><span class="pln"> will </span><span class="kwd">print</span><span class="pln"> </span><span class="kwd">this</span><span class="pln"> line</span><span class="pun">,</span><span class="pln"> because theword appears across two lines</span><span class="pun">.</span>

    这只是一个开头,或者你也可以在此基础上扩展更多的功能。sed的命令从单个看来并没是很复杂,但是要用得好就有点难度了,所以需要多多实践,多多思考,这一点跟正则表达式的学习是一样的。如果觉得没有现成的学习环境,sed1line是一个不错的开始。



0 0
原创粉丝点击