3.2. Awk 源自 Sed 和 Grep,最终源自 Ed —— 第一部分

未匹配的标注

Awk 源自 Sed 和 Grep,最终源自 Ed —— 第一部分

沿 awk 的血统之河溯流而上,你可以看到 sed 和 grep,通过这两个程序又来到 ed——最早的 UNIX 行编辑器。

你使用过一个行编辑器吗?如果有,那么你理解 sed 和 awk 的面向行将会容易得多。如果你曾经使用过 vi——一个全屏的编辑器,你将很熟悉来自于它底层的行编辑器 ex (ex 是 ed 的一个超集)的许多命令。

让我们看一些使用行编辑器 ed 的基本操作。不用担心,这是一个为了帮助你学习 sed 和 awk 的练习,不是想用行编辑器很神奇来忽悠你。 在这个练习里面出现的 ed 命令和你后面将要学习到的 sed 命令是相同的。你可以自己尝试使用 ed 来了解它是如何工作的。(如果你已经熟悉了 ed 请跳到下一章。)

要使用行编辑器,你一次只能处理一行。因此知道你现在定位在文件中的哪一行是很重要的。当你用 ed 打开一个文件,它显示了这个文件的字符数量并将你定位在最后一行。

$ ed test
2323

现在没有提示符。如果你键入一个 ed 识别不了的命令,它就会打印一个问号作为错误信息。

命令初识

打印命令 p

你可以键入打印命令 p 来显示当前行(因为是最后一行,所以什么都没有)。

p

默认一个命令只影响当前行。为了进行一个修改,你需要移动到你想要编辑的那一行,再使用命令。要移动到一行,你需要指定它的地址。一个地址可能由一个行号、一个显示文件中特定位置的符号或一个正则表达式所组成。键入行号 1 你可以到第一行。然后你可以键入删除命令,移除那一行。

1
Have you ever used a line editor? If so, it will be much easier for you to under-
d

键入 “1” 就使得第一行成为当前行,并将它显示在屏幕上。

删除命令 d

ed 的删除命令是 d,这里他删除的是当前行。除了移动到一行然后编辑它,你还可以在一个编辑命令前面加一个地址,这个地址表明这个命令作用在哪一行或哪个行的范围。如果你键入 “1d” 那么第一行就会被删掉。

你还可以指定一个正则表达式作为地址。要删除包含 regular 这个单词的行,你可以这样发出这个命令:

/regular/d

在这里斜杠分割正则表达式,“regular” 是你想要匹配的字符串。这个命令删除了包含 regular 的第一行,并且使随后的一行成为当前行。

注意:确保你理解删除命令删的是整行,它不会只删除这一行上的 “regular” 这个单词。

要删除包含正则表达式的所有行。你需要将字母 g 放到命令的前面,表示全局命令。

这个全局命令使得指定的命令作用于匹配这个正则表达式的所有行。

删除文本就讲到这里。

替换命令 s

替代文本——用一些字符替换另一些字符——要有趣得多。ed 的替代命令是 s

[address]s/pattern/replacement/flag

pattern 是一个正则表达式,它匹配一个在当前行中将被 replacement 替换的字符串。比如,下面的命令使用 “complex” 将当前行上的第一个 “regular” 替换掉:

s/regular/complex/

因为没有指明地址,所以它只影响当前行的第一个匹配。如果在当前行没有找到 “regular” 就会出现一个错误。要在一行找多个匹配,你必须指定 g 作为一个标记:

s/regular/complex/g

这个命令改变当前行上的所有匹配。替换要作用于多行必须要指明一个地址。下面的替换命令指定了一个地址。

/regular/s/regular/complex/g

这个命令影响了当前文档中匹配这个地址的第一行。记住,第一个 “regular” 是地址,第二个是执行替换命令所需要匹配的一个模式。要让替换命令应用到所有行,需要使用全局命令,将 g 放在地址前面。

g/regular/s/regular/complex/g

现在这个替换就会在任何地方进行——所有行上的所有匹配。

注意两个 g 的不同含义,开始的那个 g 是全局命令,意味着在匹配这个地址的所有行上进行改变。而末尾的这个 g 是一个标记,意味着改变一行上的每一个匹配,不仅仅是第一个匹配。

地址和模式可以不一样。

g/regular expression/s/regular/complex/g

在包含字符串 “regular expression” 的任何行上将 “regular” 替换为 “complex”。如果地址和模式是相同的,在 ed 中你可以使用两个连续的分隔符(//)来表示。

g/regular/s//complex/g

在这个例子当中,“regular” 被指定为地址和替换时要匹配的模式。

如果觉得我们介绍这些命令太快了,而且有很多需要吸收的话,不用担心,我们随后还会讲解这些命令。

命令 作用
s/regular/complex/ 替换当前行的第一个匹配
s/regular/complex/g 替换当前行的所有匹配
/regular/s/regular/complex/g 替换当前文档中匹配这个地址的第一行中的所有匹配
g/regular/s/regular/complex/g 替换当前文档中匹配这个地址的所有行的所有匹配

自编小例

$ echo "This is a regular test. regular test is this.
hello wolrd
dsfdsk
djfkdkgjkdskfds
regular test is regular." > test2

现在,使用 ed 进入 test2

➜  tmp.O6aFkdKM ed test2
106
1
This is a regular test. regular test is this.
2
hello wolrd
3
dsfdsk
4
djfkdkgjkdskfds
5
regular test is regular.
6
?

按行号输出各行内容,共有5行,输入6就报错(问号 )。

替换当前行的第一个匹配

1
This is a regular test. regular test is this.
s/regular/complex/
p
This is a complex test. regular test is this.

替换当前行的所有匹配

退出文件,再次进入:

➜  tmp.O6aFkdKM ed test2
106
1
This is a regular test. regular test is this.
s/regular/complex/g
p
This is a complex test. complex test is this.

替换当前文档中匹配这个地址的第一行中的所有匹配

退出文件,再次进入:

➜  tmp.O6aFkdKM ed test2
106
1
This is a regular test. regular test is this.
5
regular test is regular.
/regular/s/regular/complex/g
1
This is a complex test. complex test is this.
5
regular test is regular.

替换当前文档中匹配这个地址的所有行的所有匹配

退出文件,再次进入:

➜  tmp.O6aFkdKM ed test2
106
1
This is a regular test. regular test is this.
5
regular test is regular.
g/regular/s/regular/complex/g
1
This is a complex test. complex test is this.
5
complex test is complex.

注意事项

  1. g/regular/s/regular/complex/g 还可以写为 ,s/regular/complex/gg/regular/s//complex/g

    A typical command might look like: ,s/old/new/g which replaces all occurrences of the string old with new.

  2. ed 命令操作的是编辑器的缓冲区,并没有直接改变文件本身,退出时如果不使用 w 命令保存,改变将会丢失。

    If invoked with a file argument, then a copy of file is read into the editor's
    buffer. Changes are made to this copy and not directly to file itself. Upon
    quitting ed, any changes not explicitly saved with a w command are lost.

  3. ed 中的命令是单字母。

本文章首发在 LearnKu.com 网站上。

上一篇 下一篇
讨论数量: 0
发起讨论 只看当前版本


暂无话题~