sed 高级命令
前面写了一篇文章,关于sed 基础命令的介绍及操作可以查看: sed 基础命令 ;好吧,我们来看看sed 的高级命令,丫的,太多文字了….. 希望你能看明白
sed 和 awk 系列文章:
sed 基础命令:http://www.huangdc.com/109
sed 高级命令:http://www.huangdc.com/123
awk 基础命令 : http://www.huangdc.com/143
awk 高级命令:http://www.huangdc.com/146
高级的sed命令需要更大的决心来掌握,一旦你理解了这些命令,那么就可以认为自己是真正的sed主人了
处理多行模式空间(N、D、P)
采用保持空间来保存模式空间的内容并使用它可用于后续的命令(H、h、G、g、x)
编写使用分支和条件指令的脚本来更改控制流(:、b、t)
高级脚本都做一件共同的事,那就是它们改变了执行或控制的流程顺序。简单的说,就是我们sed 匹配到一行后,可以先做其他的操作(也就是所谓多行模式空间)
通常,一行被读入模式空间并且用脚本的每个命令(一个接着一个的)应用于那 一行。当达到脚本的底部时,输出这一行并且清空模式空间。然后新行被读入模式 空间,并且控制被转移回脚本的顶端。这是sed脚本中正常的控制流。而高级脚本由于各种原因中断或暂停了正常的控制流
高级的sed命令: (先浏览一下)
命令 | 缩写 | 功能 |
---|---|---|
Next | N | 多行Next(N)命令通过读取新的输入行,并将它添加到模式空间的现有内容之后来 创建多行模式空间 |
Delete | D | 删除模式空间中直到第一个嵌入的换行符的这部分内 容 |
P | 输出多行模式空间的第一部分, 直到第一个嵌入的换行符为止 | |
Hold | h 或 H | 将模式空间的内容复制或追加到保持空间 |
Get | g 或 G | 将保持空间的内容复制或追加到模式空间 |
Exchange | x | 交换保持空间和模式空间的内容 |
: | : | 标签是任意不多于7个字符的序列 |
Branch | b | 用于在脚本中将控制转移到另一行 |
Test | t | 用于在脚本中将控制转移到另一行 |
多行模式空间
多行模式空间内容如下:
^The first line\nThe second line$
1、追加下一行(N)
多行Next(N)命令通过读取新的输入行,并将它添加到模式空间的现有内容之后来 创建多行模式空间。模式空间最初的内容和新的输入行之间用换行符分割。在模式 空间中嵌入的换行符可以利用转义序列”\n”来匹配。在多行模式空间中,元字符”^” 匹配空间中第一个字条,而不是匹配换行符后面的字符。同样,”$”只匹配模式空间 中最后的换行符,而不是匹配任何嵌入的换行符。
也就是说追加一行后,模式空间的内容变成了多行模式:
^The first line\nThe second line$
举个例子:
## 将文本Subscription Services 替换成 Sub Ser ;因为 Subscription Services 分布在文件的2行上,所以需要采用 多行模式空间匹配
DcHuang@linux-fh38:~> cat 1.txt
My VMware gives you 24/7 access to your Subscription
Services and account details. From one convenient location,
you can: purchase add-on services, view order history,
see your service status, receive alerts, and track billing and renewals.
DcHuang@linux-fh38:~>
DcHuang@linux-fh38:~> sed '/Subscription$/{$!N;s/Subscription\nServices/Sub\nSer/}' 1.txt
My VMware gives you 24/7 access to your Sub
Ser and account details. From one convenient location,
you can: purchase add-on services, view order history,
see your service status, receive alerts, and track billing and renewals.
2、多行删除(D)
删除命令(d) 删除模式空间的内容并导致读入新的输入行,从而在脚本的顶端重新使 用编辑方法
删除命令(D) 稍微有些不同:它删除模式空间中直到第一个嵌入的换行符的这部分内 容。它不会导致读入新的输入行,相反,它返回到脚本的顶端,将这些指令应用于 模式空间剩余的内容。
也就是说,大写D 多行删除命令将会删除多行模式空间的 红色这部分内容
^The first line\nThe second line$
我们来看看例子 (将多个空行减少到一行); d 和 D 比较,采用D 正确
## 示例文件 1.txt
DcHuang@linux-fh38:~> cat 1.txt
This line is followed by 1 blank line.
This line is followed by 2 blank line.
This line is followed by 3 blank line.
This line is followed by 4 blank line.
This is the end.
3、多行打印(P)
多行打印(P)命令与小写的p命令稍有不同。该命令输出多行模式空间的第一部分, 直到第一个嵌入的换行符为止。在执行完脚本的最后一个命令之后,模式空间的内 容自动输出(-n选项或#n抑制这个默认的动作)。
也就是说,大写P 多行打印命令将会打印多行模式空间的 红色这部分内容
^The first line\nThe second line$
看个例子:
DcHuang@linux-fh38:~> cat 1.txt
This line is followed by 1 blank line.
This line is followed by 2 blank line.
This line is followed by 3 blank line.
This line is followed by 4 blank line.
This is the end.
包含那一行(保持空间)
采用保持空间来保存模式空间的内容并使用它可用于后续的命令(H、h、G、g、x)
模式空间是容纳当前输入行的缓冲区。还有一个称为保持空间(hold space)的顶留 (set-aside)缓冲区。模式空间的内容可以复制到保持空间,而且保持空间的内容也 可以复制到模式空间。有一组命令用于在保持空间和模式空间之间移动数据。保持 空间用于临时存储。单独的命令不能寻址保持空间或更改他的内容保持空间的常的 用途是,当改变模式空间中的原始内容是,用于保留当前输入行的副本。影响模式 空间的命令有:(同一命令小写字母和大写字母之间的差别是:小写字母命令改写 目的缓存区的内容,而大写字母命令追加缓存区的现有内容)
命令 | 缩写 | 功能 |
---|---|---|
Hold | h 或 H | 将模式空间的内容复制或追加到保持空间 |
Get | g 或 G | 将保持空间的内容复制或追加到模式空间 |
Exchange | x | 交换保持空间和模式空间的内容 |
实例:目的是颠倒以1开始的行和以2开始的行的顺序
[DcHuang@local167 ~]$ cat 1.txt
111
222
111111
222222
111111111
222222222
流控制命令(:、b、t)
编写使用分支和条件指令的脚本来更改控制流(:、b、t)
分支(b)和测试(t) 命令将脚本中的控制转移到包含特殊标签的行,如何没有指定 标签,则将控制转移到脚本的结尾处。分支命令用于无条件转移,测试命令用于有 条件转移,它们只有当替换命令改变当前行时才会执行
标签是任意不多于7个字符的序列。标签本身占据一行并以冒号开始:
:mylabel
在冒号和标签之间不允许有空格,行结尾处空格将被认为标签的一部分。
当分支命令或者测试命令中指定标签是,在命令和标签之间允许有空格:
b mylabel
1、分支命令(b)
分支命令(b) branch命令用于在脚本中将控制转移到另一行
[address]b[label]
label 是可选的,如果没有给出label,控制就被转到脚本的结尾处。如果有label就 继续执行标签后面的行
[DcHuang@local167 ~]$ cat test.txt
路人甲 1
路人BB 2
路人CC 3
路人BB 2
路人DD 4
[DcHuang@local167 ~]$ sed '/BB/{:my_label s/DD/Huangdc / ; N;/DD/b my_label}' test.txt
路人甲 1
路人BB 2
路人CC 3
路人BB 2
路人Huangdc 4
### 1、匹配BB 关键字,然后N 读取下一行,如果匹配 DD ,则返回到 my_label 执行命令
### 2、my_label 接着讲 DD 替换为 Huangdc
##
2、测试命令(t)
如果在当前匹配地址的行上进行了成功的替换,那么test命令就会转到标签(或者 脚本的结尾)处。test命令语法如下:
[address]t[label]
label 是可选的,如果没有给出label,控制就被转到脚本的结尾处。如果有label就 继续执行标签后面的行
[DcHuang@local167 ~]$ cat test.txt
路人甲 1
路人BB 2
路人CC 3
路人BB 2
路人CC 4
[DcHuang@local167 ~]$ sed '/3/{ :my_label s/C/K/ ; s/C/d/ ; t my_label ; s/C/T/ }' test.txt
路人甲 1
路人BB 2
路人Kd 3
路人BB 2
路人CC 4
### 匹配包含4 的行,将第一个 D 替换为 K ,第二个 D 替换 d ; 因为包含4的行 没有D,所以测试失败,执行将第一个 C 替换为 T
[DcHuang@local167 ~]$ sed '/4/{ :my_label s/D/K/ ; s/D/d/ ; t my_label ; s/C/T/ }' test.txt
路人甲 1
路人BB 2
路人CC 3
路人BB 2
路人TC 4
### 匹配包含3 的行,将第一个 C 替换为 K ,第二个 C 替换 d ; 因为包含3的行有 D,所以测试失败,执行将第一个 C 替换为 T
[DcHuang@local167 ~]$ sed '/3/{ :my_label s/C/K/ ; s/C/d/ ; t my_label ; s/C/T/ }' test.txt
路人甲 1
路人BB 2
路人Kd 3
路人BB 2
路人CC 4