|
在《G 与 h 命令》 中已经举出了相关的例子,在这里再进行一个小结。
像如下的这种形式,不会匹配到换行符(\n) :sed 's/\n//g'
sed 's/groad\n// '
sed 's/groad\ngoogle/groad/
为什么上述语句达不到处理换行的目的?这得看 sed 是如何读入输入内容的。
sed 是个基于行处理的工具,它每次仅读入一行,除非你对它另有安排。这样一来,在任何时候,pattern space (可参考:《pattern space 和 hold space 的概念》)里也总是只有一行内容。这也就是说,对于读入 pattern space 的这一行内容,sed 会自动将其后的换行符移除;当处理相关的匹配后并打印出来时,sed 又会给它再加上换行符。因此需要注意的关键是:当该行在 pattern space 里时,它末尾是没有换行符的。
明白了上面这一点,也就容易理解 sed 不能像上述几种方式那样处理换行符了。比如说 sed 's/groad\ngoogle/groad/ 这句,sed 会分成两次分别读入 groad 和 google 这两行内容,其间根本不会遇到换行符,因此更谈不上一下子匹配 groad\ngoogle 这种情况,所以替换工作就不能被执行。
那么如何处理换行符呢?实际上 sed 已经给出了几个相关的命令:N, P, D 。
N :从输入再读入一行,然后将其追加到 pattern space 中,这样一来 pattern space 中就有了两行内容(假设之前只有一行内容),并且这两行中间会有一个换行。
P :将 pattern space 中的内容打印出来,直到第 1 个换行处(若没有新行,那就全部打印出来)。
D:删除 pattern space 里面的内容,直到第 1 个换行处(若没有新行,则全部删除);并且开启一个新的命令处理循环,也就是说,在 D 命令后面的所有语句不会被执行,而跳到命令组的开始处执行。
下面是用这几个命令来处理的一些实例:
例一:$ echo -e "welcome\nto\nwww\ngroad\nnet" | sed ':begin;$!N;s/\n//;tbegin;'welcometowwwgroadnet 删除掉所有的换行符,但保留最后一个。
例二:$ echo -e "welcome\nto\nwww\ngroad\nnet" | sed ':begin;$!N;s/\(w.w\)\n/\1/;tbegin;P;D'
welcome
to
wwwgroad
net 上面使用了标签 begin 。$!N 表示如果还没到最后一行($!),则再读入一行并放到 pattern space 中(N)。然后使用 s/\(w.w\)\n/\1/; 判断匹配,若是匹配,那么就去掉换行符(使用 \1 取代);当替换成功时,一个 t 命令又跳回到 begin 标签处执行;若是没发生替换,那么不会执行 t 跳转,而是接着往下执行 P 和 D 命令。连续执行 P 和 D 命令,也就是相当于打印 pattern space 中的 1 行然后将其清出 pattern space 。 |
|