在学习sed的时候,我们经常会被基础功能局限在单行执行操作,在 sed 命令读取缓冲区中的文本数据时,它会基于换行符的位置,将数据分成行,sed 会根据定义好的脚本命令一次处理一行数据。
但是我们也会在很多时候遇到需要对跨行数据进行命令的时候,比如说我们有时候需要在文本中查找一个很长的字符串,但是这条字符串出现在两行中,每行各包含其中的一部分,这时候使用普通的sed功能处理文本就没办法发现这种被分开的情况。
此时sed高级命令就可以有效的处理这种情况,分别是:
N 命令会将下一行文本内容添加到缓冲区已有数据之后(之间用换行符分隔),从而使前后两个文本行同时位于缓冲区中,sed 命令会将这两行数据当成一行来处理。
下面我用一个例子来演示N命令的功能
[root@localhost ~]# cat abc
jtluo
jjlll
ccbb
aaddd[root@localhost ~]# sed '/jjl/{N;s/\n/ /}' abc
jtluo
jjlll ccbb
aaddd
我们可以看到sed命令查找到含有jjl的那行文本,找到该行后,它会用N命令将下一行合并到查找到的那一行,然后用命令s将换行符替换成空格,结果就是本来是两行的文本通过命令变成了一行。
sed 不仅提供了单行删除命令(d),也提供了多行删除命令 D,其作用是只删除缓冲区中的第一行,也就是说,D 命令将缓冲区中第一个换行符(包括换行符)之前的内容删除掉。
[root@localhost ~]# cat abc
On Tuesday, the Linux System
Administrator's group meeting will be held.
All System Administrators should attend.
Thank you for your attendance.
[root@localhost ~]# sed '/^$/{N ; /System/D}' lq.txt
On Tuesday, the Linux System
Administrator's group meeting will be held.
All System Administrators should attend.
Thank you for your attendance.
sed会查找空白行,然后用 N 命令来将下一文本行添加到缓冲区。此时如果缓冲区的内容中含有单词 System,则 D 命令会删除缓冲区中的第一行。
[root@localhost ~]# cat abc
On Tuesday, the Linux System
Administrator's group meeting will be held.
All System Administrators should attend.
Thank you for your attendance.
[root@localhost ~]# sed '/^$/{N;/^\n$/D}' abc
On Tuesday, the Linux System
Administrator's group meeting will be held.
All System Administrators should attend.
Thank you for your attendance.
当遇到两个空行时,D 命令只删除两个空行中的第一个。下一次读取该脚本时,这个空行会被另一行读入模式空间。如果那行不为空,那么两行都输出,因此确保了输出一个空行。说白点就是,当模式空间中有两个空行时,只有第一个空行被删除,当一个空行后面跟有文本时,不对模式空间里的内容处理。
由于各种各样的原因,比如用户希望在某个条件下脚本中的某个命令被执行,或者希望模式空间得到保留以便下一次的处理,都有可能使得sed在处理文件的时候不按照正常的流程来进行。这个时候,sed设置了一些高级命令来满足用户的要求。
h: 将模式空间的内容复制到保持空间
H: 将模式空间的内容追加到保持空间
g: 将保持空间的内容复制到模式空间
G: 将保持空间的内容追加到模式空间
x: 把保持空间的内容和模式空间的内容进行交换
原文件
[root@localhost ~]# cat abc
hello the world
hello minger
golang
python
c/c++
linux
[root@localhost ~]# sed '2d;5g' abc
hello the world
golang
python
linux
上面的信息,sed命令在读取文件的第2行时将整行数据复制到保留空间,并将保留空间中原有的回车符覆盖了。
使用2h,5G
[root@localhost ~]# sed '2h;5G' abc
hello the world
hello minger
golang
python
c/c++
hello minger
linux
sed的正常流程是先读取数据行放入模式空间,然后匹配条件执行sed指令,如果有多个指令,则只有最后一个指令被执行后才会输出模式空间的内容,接着读取文件的一下行内容,依次类推,知道文件读取结束时退出sed程序,但是如果使用n指令,则会改变这样的正常流程,sed遇到n指令立刻输出当前的模式中的内容,直接读取输入文件的下一行数据到模式空间。
小写字母替换为大写字母
[root@localhost ~]# sed 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/' abc
HELLO THE WORLD
HELLO MINGER
GOLANG
PYTHON
C/C++
LINUX
通常,sed 程序的执行过程会从第一个脚本命令开始,一直执行到最后一个脚本命令(D 命令是个例外,它会强制 sed 返回到脚本的顶部,而不读取新的行)。sed 提供了 b 分支命令来改变命令脚本的执行流程,其结果与结构化编程类似。
命令格式:[address]b [label]
[root@localhost ~]# cat data2.txt
This is the header line.
This is the first data line.
This is the second data line.
This is the last line.
[root@localhost ~]# sed '{2,3b ; s/This is/Is this/ ; s/line./test?/}' data2.txt
Is this the header test?
This is the first data line.
This is the second data line.
Is this the last test?
可以看到,因为 b 命令未指定 label 参数,因此数据流中的第2行和第3行并没有执行那两个替换命令。