9.2 用sed转换普通文本
下面我们就为rime.txt中的文本添加一些标签,为此可以使用插入命令(i\
)。找到rime.txt文件所在的路径,在shell提示符中输入下面的命令:
sed '1 i\
<!DOCTYPE html>\
<html lang="en">\
<head>\
<title>The Rime of the Ancyent Marinere (1798)</title>\
<meta charset="utf-8"/>\
</head>\
<body>\
q' rime.txt
按回车(或Return键),输出如下所示,可以看到加在上面的标签:
<!DOCTYPE html>
<html lang="en">
<head>
<title>The Rime of the Ancyent Marinere (1798)</title>
<meta charset="utf-8"/>
</head>
<body>
THE RIME OF THE ANCYENT MARINERE, IN SEVEN PARTS.
你刚刚所键入的命令并不会实际改变文件——它只会在屏幕上产生输出。后面我会展示如何修改文件内容。
9.2.1 用sed进行替换
在下面的示例中,我们要用sed找出文件的第一行然后使用转义括号(
和)
构成的捕获分组捕获一整行。sed需要对括号进行转义后才可捕获分组,除非你使用-E
选项(稍后讨论)。行起始部分由^
标示,行结束部分由$
标示。后向引用\1
将捕获的文本放入title
元素中,并缩进一个空格。
运行以下命令:
sed '1s/^\(.*\)$/ <title>\1<\/title>/;q' rime.txt
输出结果如下所示:
<title>THE RIME OF THE ANCYENT MARINERE, IN SEVEN PARTS.</title>
现在试一下这样:
sed -E '1s/^(.*)$/<!DOCTYPE html>\
<html lang="en">\
<head>\
<title>\1<\/title>\
<\/head>\
<body>\
<h1>\1<\/h1>\
/;q' rime.txt
以下是详细分析。
-E
选项代表sed使用扩展的正则表达式(也就是ERE,因此不必对括号进行转义)。- 使用替换命令时,将第1行放入捕获分组(
^(.*)$
)因此可以通过\1
重用该内容。 - 创建HTML标签以及用
\
对换行符进行转义。 - 在
title
和h1
之间用\1
插入捕获的文本。 - 在
q
处结束程序来防止在屏幕上打印剩下的诗文。
正确的结果是:
<!DOCTYPE html>
<html lang="en">
<head>
<title>THE RIME OF THE ANCYENT MARINERE, IN SEVEN PARTS.</title>
</head>
<body>
<h1>THE RIME OF THE ANCYENT MARINERE, IN SEVEN PARTS.</h1>
9.2.2 用sed处理罗马数字
诗文分为七个部分,每一部分以一个罗马数字开头。还有一个“ARGUMENT”标题。下面一行命令会使用sed捕获标题和罗马数字,并将它们用
sed -En 's/^(ARGUMENT\.|I{0,3}V?I{0,2}\.)$/<h2>\1<\/h2>/p' rime.txt
以下就是你会看到的结果:
<h2>ARGUMENT\.</h2>
<h2>I.</h2
<h2>II.</h2
<h2>III.</h2
<h2>IV.</h2
<h2>V.</h2
<h2>VI.</h2
<h2>VII.</h2
接下来是对以上sed命令的描述。
-E
选项会使用扩展的正则表达式,而-n
选项会覆盖sed默认打印每一行的行为。- 替换命令(
s
)会捕获标题和七个大写罗马数字,其中每一个单独一行紧跟一个句号,范围为I到VII。 s
命令随后将每一行捕获的文本嵌入h2
元素中。- 替换部分末尾的
p
标志将结果打印到屏幕上。
9.2.3 用sed处理特定段落
接下来这行命令会找到第5行的段落:
sed -En '5s/^([A-Z].*)$/<p>\1<\/p>/p' rime.txt
然后将该段落放入
<p>How a Ship having passed the Line was driven by Storms to the cold Country towards
the South Pole; and how from thence she made her course to the tropical Latitude
of the Great Pacific Ocean; and of the strange things that befell; and in what
manner the Ancyent Marinere came back to his own Country.</p>
进展有点儿慢?别急,我们很快就会把这些技巧综合起来。
9.2.4 用sed处理多行诗文
接着我们使用下面的表达式来标记多行诗文:
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
命令添加标签而不是
标签。
这里是标记后的部分结果:
<p>It is an ancyent Marinere,<br/>
And he stoppeth one of three:<br/>
"By thy long grey beard and thy glittering eye<br/>
"Now wherefore stoppest me?<br/>
"The Bridegroom's doors are open'd wide<br/>
"And I am next of kin;<br/>
"The Guests are met, the Feast is set,--<br/>
"May'st hear the merry din.--<br/>
还应该用
标签替代空行来分隔诗文:
sed -E 's/^$/<br\/>/' rime.txt
下面是操作的结果:
He prayeth best who loveth best,
All things both great and small:
For the dear God, who loveth us,
He made and loveth all.
<br/>
The Marinere, whose eye is bright,
Whose beard with age is hoar,
Is gone; and now the wedding-guest
Turn'd from the bridegroom's door.
<br/>
He went, like one that hath been stunn'd
And is of sense forlorn:
A sadder and a wiser man
He rose the morrow morn.
我发现在合适的位置添加标签和空格实在太常见了。希望你也能做好。