9.2 用sed转换普通文本

下面我们就为rime.txt中的文本添加一些标签,为此可以使用插入命令(i\)。找到rime.txt文件所在的路径,在shell提示符中输入下面的命令:

  1. sed '1 i\
  2. <!DOCTYPE html>\
  3. <html lang="en">\
  4. <head>\
  5. <title>The Rime of the Ancyent Marinere (1798)</title>\
  6. <meta charset="utf-8"/>\
  7. </head>\
  8. <body>\
  9. q' rime.txt

按回车(或Return键),输出如下所示,可以看到加在上面的标签:

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <title>The Rime of the Ancyent Marinere (1798)</title>
  5. <meta charset="utf-8"/>
  6. </head>
  7. <body>
  8. THE RIME OF THE ANCYENT MARINERE, IN SEVEN PARTS.

你刚刚所键入的命令并不会实际改变文件——它只会在屏幕上产生输出。后面我会展示如何修改文件内容。

9.2.1 用sed进行替换

在下面的示例中,我们要用sed找出文件的第一行然后使用转义括号()构成的捕获分组捕获一整行。sed需要对括号进行转义后才可捕获分组,除非你使用-E选项(稍后讨论)。行起始部分由^标示,行结束部分由$标示。后向引用\1将捕获的文本放入title元素中,并缩进一个空格。

运行以下命令:

  1. sed '1s/^\(.*\)$/ <title>\1<\/title>/;q' rime.txt

输出结果如下所示:

  1. <title>THE RIME OF THE ANCYENT MARINERE, IN SEVEN PARTS.</title>

现在试一下这样:

  1. sed -E '1s/^(.*)$/<!DOCTYPE html>\
  2. <html lang="en">\
  3. <head>\
  4. <title>\1<\/title>\
  5. <\/head>\
  6. <body>\
  7. <h1>\1<\/h1>\
  8. /;q' rime.txt

以下是详细分析。

  • -E选项代表sed使用扩展的正则表达式(也就是ERE,因此不必对括号进行转义)。
  • 使用替换命令时,将第1行放入捕获分组(^(.*)$)因此可以通过\1重用该内容。
  • 创建HTML标签以及用\对换行符进行转义。
  • titleh1之间用\1插入捕获的文本。
  • q处结束程序来防止在屏幕上打印剩下的诗文。

正确的结果是:

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <title>THE RIME OF THE ANCYENT MARINERE, IN SEVEN PARTS.</title>
  5. </head>
  6. <body>
  7. <h1>THE RIME OF THE ANCYENT MARINERE, IN SEVEN PARTS.</h1>

9.2.2 用sed处理罗马数字

诗文分为七个部分,每一部分以一个罗马数字开头。还有一个“ARGUMENT”标题。下面一行命令会使用sed捕获标题和罗马数字,并将它们用

标签包括:

  1. sed -En 's/^(ARGUMENT\.|I{0,3}V?I{0,2}\.)$/<h2>\1<\/h2>/p' rime.txt

以下就是你会看到的结果:

  1. <h2>ARGUMENT\.</h2>
  2. <h2>I.</h2
  3. <h2>II.</h2
  4. <h2>III.</h2
  5. <h2>IV.</h2
  6. <h2>V.</h2
  7. <h2>VI.</h2
  8. <h2>VII.</h2

接下来是对以上sed命令的描述。

  • -E选项会使用扩展的正则表达式,而-n选项会覆盖sed默认打印每一行的行为。
  • 替换命令(s)会捕获标题和七个大写罗马数字,其中每一个单独一行紧跟一个句号,范围为I到VII。
  • s命令随后将每一行捕获的文本嵌入h2元素中。
  • 替换部分末尾的p标志将结果打印到屏幕上。

9.2.3 用sed处理特定段落

接下来这行命令会找到第5行的段落:

  1. sed -En '5s/^([A-Z].*)$/<p>\1<\/p>/p' rime.txt

然后将该段落放入

标签中:

  1. <p>How a Ship having passed the Line was driven by Storms to the cold Country towards
  2. the South Pole; and how from thence she made her course to the tropical Latitude
  3. of the Great Pacific Ocean; and of the strange things that befell; and in what
  4. manner the Ancyent Marinere came back to his own Country.</p>

进展有点儿慢?别急,我们很快就会把这些技巧综合起来。

9.2.4 用sed处理多行诗文

接着我们使用下面的表达式来标记多行诗文:

  1. sed -E '9s/^[ ]*(.*)/ <p>\1<br\/>/;10,832s/^([ ]{5,7}.*)/\1<br\/>/;833s/^(.*)/\1<\/p>/' rime.txt

这些sed命令是根据行号来实现操作的。通常情况下这种方法并不适用,但若所处理的内容已知则这种方法还是很好的。

  • 第9行(诗文的第一行,s命令会选定该行),在文字前面添加几个空格,再插入一个

    标签,然后在行尾添加一个
    标签。
  • 第10行到第832行,每个开头有5至7个空格的行之后都添加一个
    标签。
  • 在第833行(诗文的最后一行),s命令添加

    标签而不是
    标签。

这里是标记后的部分结果:

  1. <p>It is an ancyent Marinere,<br/>
  2. And he stoppeth one of three:<br/>
  3. "By thy long grey beard and thy glittering eye<br/>
  4. "Now wherefore stoppest me?<br/>
  5. "The Bridegroom's doors are open'd wide<br/>
  6. "And I am next of kin;<br/>
  7. "The Guests are met, the Feast is set,--<br/>
  8. "May'st hear the merry din.--<br/>

还应该用
标签替代空行来分隔诗文:

  1. sed -E 's/^$/<br\/>/' rime.txt

下面是操作的结果:

  1. He prayeth best who loveth best,
  2. All things both great and small:
  3. For the dear God, who loveth us,
  4. He made and loveth all.
  5. <br/>
  6. The Marinere, whose eye is bright,
  7. Whose beard with age is hoar,
  8. Is gone; and now the wedding-guest
  9. Turn'd from the bridegroom's door.
  10. <br/>
  11. He went, like one that hath been stunn'd
  12. And is of sense forlorn:
  13. A sadder and a wiser man
  14. He rose the morrow morn.

我发现在合适的位置添加标签和空格实在太常见了。希望你也能做好。