程序员肖邦的博客 享受编程和技术所带来的快乐

sed入门教程系列之:数字定址和正则定址

2017-01-20
肖邦

sed 是一个比较古老的,功能十分强大的用于文本处理的流编辑器,加上正则表达式的支持,可以进行大量的复杂的文本编辑操作。sed 本身是一个非常复杂的工具,有专门的书籍讲解 sed 的具体用法,但是个人觉得没有必要去学习它的每个细节,那样没有特别大的实际意义。网上也有很多关于 sed 的教程,我也是以学以致用的心态来学习 sed 的常见的用法,并进行系统的总结,内容基本覆盖了 sed 的大部分的知识点。文中的内容比较简练,加以实际示例来帮助去理解 sed 的使用。

本系列文章目录:

数字定址和正则定址

1、关于定址的概念

默认情况下 sed 会对每一行内容进行匹配、处理、输出,某些情况不需要对处理的文本全部编辑,只需要其中的一部分,比如 1-10 行,偶数行,或者是包含 “hello” 字符串的行,这种情况下就需要我们去定位特定的行来处理,而不是全部内容,这里把这个定位指定的行叫做 “定址”。

2、数字定址

数字定址其实就是通过数字去指定具体要操作编辑的行,数字定址有几种方式,每种方式都有不同的应用场景,下边以举例的方式来描述每种数字定址的用法。

例子1:

$ sed –n '4s/hello/A/' message

说明:将第 4 行中 hello 字符串替换为 A,其它行如果有 hello 也不会被替换。

例子2:

$ sed –n '2,4s/hello/A/' message

说明:将第 2-4 行中 hello 字符串替换为 A,其它行如果有 hello 也不会被替换。

例子3:

$ sed –n '2,+4s/hello/A/' message

说明:从第 2 行开始,再接着往下数 4 行,也就是 2-6 行,这些行会把 hello 字符替换为 A。

例子4:

$ sed –n '4,~3s/hello/A/' message

说明:第 4 行开始,到第 6 行。解释 6 的由来,”4,~3” 表示从 4 行开始到下一个 3 的倍数,这里从 4 开始算,那就是 6 了,当然 9 就不是了,因为是要求 3 的第一个超过前边数字 4 的倍数,感觉这种适用场景不会太多。

例子5:

$ sed –n '4~3s/hello/A/' message

说明:从第 4 行开始,每隔 3 行就把 hello 替换为 A。比如从 4 行开始,7 行,10 行等依次 +3 行。这个比较常用,比如 3 替换为 2 的时候,也就是每隔 2 行的步调,可以实现奇数和偶数行的操作。

例子6:

$ sed –n '$s/hello/A/' message

说明:$ 符号表示最后一行,和正则中的 $ 符号类似,但是第 1 行不用 ^ 表示,直接 1 就行了。

例子7:

$ sed -n '1!s/hello/A/' message

说明:! 符号表示取反,该命令是将除了第 1 行,其它行 hello 替换为 A,上述定址方式也可以使用 ! 符号。

3、正则定址

正则定址使用目的和数字定址完全一样,使用方式上有所不同,是通过正则表达式的匹配来确定需要处理编辑哪些行,其它行就不需要额外处理。

例子1:

$sed -n '/nihao/d' message

说明:将匹配到 nihao 的行执行删除操作。

例子2:

$ sed -n '/^$/d' message

说明:删除空行

例子3:

$ sed -n '/^TS/,/^TE/d' message

说明:匹配以 TS 开头的行到 TE 开头的行之间的行,把匹配到的这些行删除。

4、数字定址和正则定址混用

其实数字定址和正则定址可以配合使用,参考下边的例子。

例子1:

$ sed -n '1,/^TS/d' message

说明:匹配从第 1 行到 TS 开头的行,把匹配的行删除。

5、关于定址的分组命令

例子1:

/^TS/,/^TE/{
s/CN/China/
s/Beijing/BJ/
} 

说明:该命令表示将从 TS 开头的行到 TE 开头的行之间范围的行内容中 CN 替换为 China,并且把 Beijing 替换为 BJ,类似于多命令之间用分号的那种方式,不过这样定址代码只写了一遍,相当于执行了一条子命令。

例子2:

$ sed -n '2,3s{/cn/china/;/a/b/}' message

说明:效果类似例子 1,有点数学上的乘法分配率的意思。

6、sed定址的总结

  • sed 默认的命令执行范围是全局编辑的,如果不明确指定行的话,命令会在所有输入行上执行,如果想仅对其中部分行执行命令,可以使用地址限制。

  • 如果给了 2 个地址,即地址对(地址范围),则命令匹配的这个地址范围内执行,但是需要注意的是:对于像 “addr1,addr2” 这种形式的地址匹配,如果addr1 匹配,则匹配成功,”开关”打开,在该行上执行命令,此时不管 addr2 是否匹配,即使 addr2 在 addr1 这一行之前;

  • 接下来读入下一行,如果addr2 匹配,则执行命令,同样开关”关闭”;

  • 如果 addr2 在 addr1 之后,则一直处理到匹配为止,换句话说,如果 addr2 一直不匹配,则开关一直不关闭,因此会持续执行命令到最后一行。


Comments

Content