sed 多行命令在学习 sed 命令的基础功能时,你可能注意到了一个局限,即所有的 sed 命令都只是针对单行数据执行 *** 作,在 sed 命令读取缓冲区中的文本数据时,它会基于换行符的位置,将数据分成行,sed 会根据定义好的脚本命令一次处理一行数据。
但是,有时我们需要对跨多行的数据执行特定 *** 作。比如说,在文本中查找一串字符串
"http://c.biancheng.net"
,它很有可能出现在两行中,每行各包含其中一部分。这时,如果用普通的 sed 编辑器命令来处理文本,就不可能发现这种被分开的情况。幸运的是,sed 命令的设计人员已经考虑到了这种情况,并设计了对应的解决方案。sed 包含了三个可用来处理多行文本的特殊命令,分别是:
Next 命令(N):将数据流中的下一行加进来创建一个多行组来处理。Delete(D):删除多行组中的一行。Print(P):打印多行组中的一行。
注意,以上命令的缩写,都为大写。
N 多行 *** 作命令N 命令会将下一行文本内容添加到缓冲区已有数据之后(之间用换行符分隔),从而使前后两个文本行同时位于缓冲区中,sed 命令会将这两行数据当成一行来处理。下面这个例子演示的 N 命令的功能:
[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 '/first/{ N ; s/\n/ / }' 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 ~]# cat data3.txt
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 ; s/System administrator/Desktop User/' data3.txt
On Tuesday,the linux Desktop User's group meeting will be held.
All Desktop Users should attend.
Thank you for your attendance.
要解决这个问题,可以在 sed 脚本中用两个替换命令,一个用来匹配短语出现在多行中的情况,一个用来匹配短语出现在单行中的情况,比如:
[root@localhost ~]# sed 'N
> s/System\nadministrator/Desktop\nUser/
> s/System administrator/Desktop User/
> ' data3.txt
On Tuesday,the linux Desktop
User's group meeting will be held.
All Desktop Users should attend.
Thank you for your attendance.
但这个脚本中仍有个小问题,即它总是在执行 sed 命令前将下一行文本读入到缓冲区中,当它到了后一行文本时,就没有下一行可读了,此时 N 命令会叫 sed 程序停止,这就导致,如果要匹配的文本正好在最后一行中,sed 命令将不会发现要匹配的数据。
解决这个 BUG 的方法是,将单行命令放到 N 命令前面,将多行命令放到 N 命令后面,像这样:
[root@localhost ~]# sed '
> s/System\nadministrator/Desktop\nUser/
> N
> s/System administrator/Desktop User/
> ' data3.txt
On Tuesday,the linux Desktop
User's group meeting will be held.
All Desktop Users should attend.
Thank you for your attendance.
D 多行删除命令sed 不仅提供了单行删除命令(d),也提供了多行删除命令 D,其作用是只删除缓冲区中的第一行,也就是说,D 命令将缓冲区中第一个换行符(包括换行符)之前的内容删除掉。
比如说:
[root@localhost ~]# cat data4.txt
On Tuesday,the linux System
administrator's group meeting will be held.
All System administrators should attend.
[root@localhost ~]# sed 'N ; /System\nadministrator/D' data4.txt
administrator's group meeting will be held.
All System administrators should attend.
下面的例子中,它会删除数据流中出现在第一行前的空白行:
[root@localhost ~]# cat data5.txt
This is the header line.
This is a data line.
This is the last line.
[root@localhost ~]# sed '/^$/{N ; /header/D}' data5.txt
This is the header line.
This is a data line.
This is the last line.
P 多行打印命令同 d 和 D 之间的区别一样,P(大写)命令和单行打印命令 p(小写)不同,对于具有多行数据的缓冲区来说,它只会打印缓冲区中的第一行,也就是首个换行符之前的所有内容。
例如,test.txt 文件中的内容如下:
[root@localhost ~]# cat test.txt
aaa
bbb
ccc
ddd
eee
fff
表 1 中是对 test.txt 文件中的内容分别用 p 命令和 P 命令后,产生的输出信息的对比。
P(大写)命令 | p(小写)命令 |
---|---|
[root@localhost ~]# sed '/.*/N;P' | [root@localhost ~]# sed '/.*/N;p' |
第一个 sed 命令,每次都使用 N 将下一行内容追加到缓冲区内容的后面(用换行符间隔),也就是说,第一次时缓冲区中的内容为 aaa\nbbb,但 P(大写) 命令的作用的打印换行符之前的内容,也就是 aaa,之后则是 sed 在自动输出功能输出 aaa 和 bbb(sed 命令会自动将 \n 输出为换行),依次类推,就输出了所看到的结果。
第二个 sed 命令,使用的是 p (小写)单行打印命令,它会将缓冲区中的所有内容全部打印出来(\n 会自动输出为换行),因此,出现了看到的结果。sed 保持空间前面我们一直说,sed 命令处理的是缓冲区中的内容,其实这里的缓冲区,应称为模式空间。值得一提的是,模式空间并不是 sed 命令保存文件的唯一空间。sed 还有另一块称为保持空间的缓冲区域,它可以用来临时存储一些数据。
表 2 列出了 5 条可用来 *** 作保持空间的命令。
命令 | 功能 |
---|---|
h | 将模式空间中的内容复制到保持空间 |
H | 将模式空间中的内容附加到保持空间 |
g | 将保持空间中的内容复制到模式空间 |
G | 将保持空间中的内容附加到模式空间 |
x | 交换模式空间和保持空间中的内容 |
通常,在使用 h 或 H 命令将字符串移动到保持空间后,最终还要用 g、G 或 x 命令将保存的字符串移回模式空间。保持空间最直接的作用是,一旦我们将模式空间中所有的文件复制到保持空间中,就可以清空模式空间来加载其他要处理的文本内容。
由于有两个缓冲区域,下面的例子中演示了如何用 h 和 g 命令来将数据在 sed 缓冲区之间移动。
[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 -n '/first/ {h ; p ; n ; p ; g ; p }' data2.txt
This is the first data line.
This is the second data line.
This is the first data line.
b 分支命令基本格式为:
[address]b [label]
其中,address 参数决定了哪些行的数据会触发分支命令,label 参数定义了要跳转到的位置。需要注意的是,如果没有加 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,最多为 7 个字符长度)。在使用此该标签时,要以冒号开始(比如 :label2),并将其放到要跳过的脚本命令之后。这样,当 sed 命令匹配并处理该行文本时,会跳过标签之前所有的脚本命令,但会执行标签之后的脚本命令。
比如说:
[root@localhost ~]# sed '{/first/b jump1 ; s/This is the/No jump on/
> :jump1
> s/This is the/Jump here on/}' data2.txt
No jump on header line
Jump here on first data line
No jump on second data line
No jump on last line
b 分支命令除了可以向后跳转,还可以向前跳转,例如:
[root@localhost ~]# echo "This,is,a,test,to,remove,commas." | sed -n '{
> :start
> s/,//1p
> /,/b start
> }'
This is,commas.
This is a,commas.
This is a test,commas.
This is a test to,commas.
This is a test to remove,commas.
This is a test to remove commas.
t 测试命令类似于 b 分支命令,t 命令也可以用来改变 sed 脚本的执行流程。t 测试命令会根据 s 替换命令的结果,如果匹配并替换成功,则脚本的执行会跳转到指定的标签;反之,t 命令无效。
测试命令使用与分支命令相同的格式:
[address]t [label]
跟分支命令一样,在没有指定标签的情况下,如果 s 命令替换成功,sed 会跳转到脚本的结尾(相当于不执行任何脚本命令)。例如:[root@localhost ~]# sed '{
> s/first/matched/
> t
> s/This is the/No match on/
> }' data2.txt
No match on header line
This is the matched data line
No match on second data line
No match on last line
再举个例子:
[root@localhost ~]# echo "This,commas. " | sed -n '{
> :start
> s/,//1p
> t start
> }'
This is,commas.
This is a test to remove commas.
以上是内存溢出为你收集整理的Linux sed命令高级用法精讲全部内容,希望文章能够帮你解决Linux sed命令高级用法精讲所遇到的程序开发问题。
如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)