十七、sed进阶

前言

哦,sed进阶我的痛,从开学到一脸懵逼,到再拿起,到放弃,再到最后学完,三处没懂。

这三个例子没有搞明白,分别是:

排除命令!中的倒叙文本例子
删除结尾空白行
实时打印最后一行

 

模式空间

 是一块活跃的缓冲区,用于sed数据处理时保存待检查文本的区域。

sed做数据处理是读取文档的一行至模式空间,然后对该行执行sed命令,命令完成后输出该行并清空模式空间。

所以说sed编辑器对文本的操作是不会影响到实际文件的,只会影响到模式空间里的数据。

 

n命令移动到下一行

举例:删除第二个空行

sed命令读取文本到模式空间中,查找这一行含有header字符串的文本行,找到则执行n命令,读取下一行到模式空间中。

[root@tzPC 21Unit]# cat data1.txt 
This is the header line.

This is a data line.
[root@tzPC 21Unit]# sed '/header/{n ; d}' data1.txt 
This is the header line.
This is a data line.

 

 N命令多行操作

多行版本的N命令会将下一文本行添加到模式空间中现有文本后。

模式空间最初内容与新的输入行之间使用换行符分隔,可使用\n匹配。

 

样本文件data2.txt

[root@tzPC 21Unit]# 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.

 匹配first那一行并使用N命令读取下一行到模式空间中

[root@tzPC 21Unit]# sed -n '/first/{N ; p}' data2.txt 
This is the first data line.
This is the second data line.

匹配包含first行并使用N命令读取下一行替换掉换行符号

[root@tzPC 21Unit]# 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.

 

举例:处理分散在两行的数据使他们合并在一行

样本文件data3.txt

[root@tzPC 21Unit]# 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.

 可以看到第一行中的System跟Administrator分别在不同行,可以使用通配符. 来匹配空格或换行符等任意单个字符

[root@tzPC 21Unit]# 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.

处理分散在两行的数据并修改

[root@tzPC 21Unit]# 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.

 

注意:如果文本在最后一行,N命令无法读取这一行文本的下一行,则会让sed编辑器停止工作,最后一行就改不了

如样本文件data4.txt

[root@tzPC 21Unit]# cat data4.txt
On Tuesday, the Linux System
Administrator's group meeting will be held.
All System Administrators should attend.

 System Administrators在最后一行,需要改为Desktop User,这时可以这样处理

[root@tzPC 21Unit]# sed '
> s/System Administrator/Desktop User/
> N
> s/System\nAdministrator/Desktop\nUser/
> ' data4.txt
On Tuesday, the Linux Desktop
User's group meeting will be held.
All Desktop Users should attend.

先使用单行替换,在使用多行替换解决问题。

 

 这个例子加深印象

样本文件data2.txt

[root@tzPC 21Unit]# 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.

 关于n跟N

[root@tzPC 21Unit]# sed -n '/first/{p;N;p}' data2.txt 
This is the first data line.
This is the first data line.
This is the second data line.
/*
sed编辑器读取第一行文本,执行匹配first指令,当然第一行没有文本first,sed会输出第一行文本,但是-n禁止了sed的自动打印,结果就是sed清空了模式空间;
sed读取第二行文本,继续执行指令,匹配到first,执行打印命令p,输出了此行,然后使用N命令读取下一行到模式空间,再执行p命令打印,结果就是输出了两行,随机清空模式空间;
剩下的两行不包含first文本,即不输出了
*/

[root@tzPC 21Unit]# sed -n '/first/{p;n;p}' data2.txt 
This is the first data line.
This is the second data line.
/*
sed编辑器读取第一行,执行匹配first指令,当然第一行没有文本first,sed会输出第一行文本,但是-n禁止了sed的自动打印,结果就是sed清空了模式空间;
sed读取第二行文本,继续执行指令,匹配到first,执行打印命令p,输出了此行,然后清空模式空间,执行n命令读取下一行,执行p命令打印,结果就输出了2行,随即清空了模式空间;
*/

[root@tzPC 21Unit]# sed -n '/first/{p;N;P}' data2.txt 
This is the first data line.
This is the first data line.
/*
多行打印P命令只输出模式空间中第一行
此时模式空间中有两行,即first匹配到的一行,N命令读取的下一行,P打印的是第一行
*/

可以参考:点此传送

 

多行删除命令D

单行删除命令d用来删除模式空间中的内容,如果跟N命令一起使用会删除两行。

多行删除命令D用来删除模式空间的第一行,从头到换行符结尾所有字符。

样本文件data4.txt

[root@tzPC 21Unit]# cat data4.txt
On Tuesday, the Linux System
Administrator's group meeting will be held.
All System Administrators should attend.

sed将第一行放入模式空间,使用N读取下一行放入模式空间,d命令把这两行全部带走,就只会输出sed读取到的第三行并自动打印出来。

而使用D只会删除模式空间的第一行。

[root@tzPC 21Unit]# sed 'N ; /System\nAdministrator/d' data4.txt
All System Administrators should attend.
[root@tzPC 21Unit]# sed 'N ; /System\nAdministrator/D' data4.txt
Administrator's group meeting will be held.
All System Administrators should attend.

 

举例:删除第一行前的空白行

样本文件data5.txt

[root@tzPC 21Unit]# cat data5.txt 

This is the header line.
This is a data line.

This is the last line.

脚本

[root@tzPC 21Unit]# sed '/^$/{N ; /header/D}' data5.txt
This is the header line.
This is a data line.

This is the last line.

 

多行打印命令P

只打印多行模式空间中的第一行。

样本文件data3.txt

[root@tzPC 21Unit]# 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.

脚本

#使用P命令只会打印模式空间中的第一行
[root@tzPC 21Unit]# sed -n 'N ; /System\nAdministrator/P' data3.txt
On Tuesday, the Linux System
#使用p命令会把模式空间中的所有文本都打印出来
[root@tzPC 21Unit]# sed -n 'N ; /System\nAdministrator/p' data3.txt
On Tuesday, the Linux System
Administrator's group meeting will be held.

 

保持空间

属于sed编辑器另一块缓冲区域,可以用它临时保存模式空间中处理的行。

 

保持空间命令

命令 描述
h 从模式空间复制到保持空间
H 从模式空间追加到保持空间
g 从保持空间复制到模式空间
G 从保持空间追加到模式空间
x

交换模式空间和保持空间的内容

样本文件data2.txt

[root@tzPC 21Unit]# 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@tzPC 21Unit]# 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.

执行的具体过程不说了,自学就是这样,从开始的懵逼,到略懂,再到明白的时候才发现原来的问题是多么的简单,只是想的复杂了而已!

 可以通过保持空间对文本进行倒序输出。

 

排除命令!

negate排除

让原本起作用的命令不起作用。

 

样本文件data2.txt

[root@tzPC 21Unit]# 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.

打印除header的行

[root@tzPC 21Unit]# sed -n '/header/!p' data2.txt
This is the first data line.
This is the second data line.
This is the last line.

也可配合N对最后一行进行操作,如下

样本文件data4.txt

[root@tzPC 21Unit]# cat data4.txt
On Tuesday, the Linux System
Administrator's group meeting will be held.
All System Administrators should attend.

 脚本

[root@tzPC 21Unit]# sed '$N;
> s/System\nAdministrator/Desktop\nUser/
> s/System Administrator/Desktop User/
> ' data4.txt
On Tuesday, the Linux System
Administrator's group meeting will be held.
All System Administrators should attend.

$N表示最后一行不执行N命令。

 

 我卡在了这个例子上一直没搞明白他是怎么个反转过程

于2023年7月21日重新学习,已经解决,哈哈

样本文本data2.txt

[root@tzPC 21Unit]# 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@tzPC 21Unit]# sed -n '{1!G ; h ; $p}' data2.txt
This is the last line.
This is the second data line.
This is the first data line.
This is the header line.

tac也能实现此功能,该命令是cat的反写

[root@tzPC 21Unit]# tac data2.txt
This is the last line.
This is the second data line.
This is the first data line.
This is the header line.

 

分支命令b

branch分支的简写

语法

[address]b [label]

address参数定义哪些行会触发分支命令,label定义要跳转到的位置,如果不指定label则命令会直接跳转到脚本的结尾。

 

样本文件data2.txt

[root@tzPC 21Unit]# 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.

让sed在2,3行触发分支命令,跳过后续的替换命令

[root@tzPC 21Unit]# 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?

 

如下案例中,如果匹配到first则跳转到标签为jump1后的脚本执行s/This is the/Jump here on/命令,如果没有匹配到first则执行后续的s/This is the/No jump on/命令。

此为跳转到sed脚本后面的标签

同样使用样本文件data2.txt

[root@tzPC 21Unit]# 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.

 

也可以跳转到脚本靠前的标签上

[root@tzPC 21Unit]# echo "This, is, a, test, to, remove, commas." | sed -n '{
:start
s/,//1p
> b start
> }'
This is, a, test, to, remove, commas.
This is a, test, to, remove, commas.
This is a test, to, remove, commas.
This is a test to, remove, commas.
This is a test to remove, commas.
This is a test to remove commas.

脚本每次迭代都会删除文本中的第一个逗号并打印,他永远不会结束,只能手动停止脚本。

可以修改成如下

[root@tzPC 21Unit]# echo "This, is, a, test, to, remove, commas." | sed -n '{
> :start
> s/,//1p
> /,/b start
> }'
This is, a, test, to, remove, commas.
This is a, test, to, remove, commas.
This is a test, to, remove, commas.
This is a test to, remove, commas.
This is a test to remove, commas.
This is a test to remove commas.

这样分支命令只有在行中有逗号时才会跳转,在最后一个逗号被删除后,分支命令就不再运行,脚本就停止了。

 

测试命令test

测试命令t会根据替换命令的结果跳转到某个标签。

语法跟分支命令b一样

使用样本文件data2.txt

[root@tzPC 21Unit]# 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@tzPC 21Unit]# echo "This, is, a, test, to, remove, commas." | sed -n '{
> :start
> s/,//1p
> t start
> }'
This is, a, test, to, remove, commas.
This is a, test, to, remove, commas.
This is a test, to, remove, commas.
This is a test to, remove, commas.
This is a test to remove, commas.
This is a test to remove commas.
[root@tzPC 21Unit]# 

相当于s/,//1p执行成功了t命令才会跳转到后面的标签,如果没有成功则退出了。

 

模式替代命令&

&符号可以用来代表替换命令中匹配的模式。

[root@tzPC 21Unit]# echo "The cat sleeps in his hat." | sed 's/.at/"&"/g'
The "cat" sleeps in his "hat".

此案例中,&代替了前面的匹配模式.at,使其匹配到的cat跟hat都替换为"cat"跟"hat"

 

替代单独字符()

&命令会代替匹配模式中整个字符串,如果想只代替整个字符串的一部分时,可以使用()

()用来定义替换模式中的子模式,使用时必须添加反斜杠进行转义。

替代字符使用反斜杠加数字组成,第一个子模式的替代字符为\1,第二个为\2

[root@tzPC 21Unit]# echo "The System Administrator manual" | sed '
> s/\(System\) Administrator/\1 User/'
The System User manual

案例中,System被定义为一个子模式,然后在后续替代字符中使用\1来标识第一个匹配的子模式System

这在通配符中使用尤其有用

[root@tzPC 21Unit]# echo "That furry cat is pretty" |sed 's/furry \(.at\)/\1/'
That cat is pretty

 

使用多个子模式案例

[root@tzPC ~]# echo "1234567" | sed '{
> :start
> s/\(.*[0-9]\)\([0-9]\{3\}\)/\1,\2/
> t start
> }'
1,234,567

这个例子匹配两个模式

.*[0-9]  #以数字结尾任意长度的字符

[0-9]{3}  #匹配任意三个数字

分别使用\1,\2来标识这两个匹配模式,如果这两个模式匹配上了,就会在他们之间加一个逗号。

 

包装脚本

 也就是把sed命令写成脚本文件,传个参数进去

[root@tzPC 21Unit]# cat reverse.sh 
#!/bin/bash
#Shell wrapper for sed editor script.
#sed编辑器脚本的shell包装
# to reverse text file lines.
#反转文件文本行
#
sed -n '{ 1!G ; h ; $p}' $1

 

重定向sed输出

 使用$()

 

加倍行间距

启动sed编辑器时,保持空间只有一个空行,可以使用G将保持空间追加到模式空间后,依此完成多个空行。

[root@tzPC 21Unit]# sed 'G' 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@tzPC 21Unit]# 

使用$!来让最后一行不追加空行

[root@tzPC 21Unit]# sed '$!G' 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@tzPC 21Unit]# 

 

样本文本data6.txt

[root@tzPC 21Unit]# cat data6.txt
This is line one.
This is line two.

This is line three.
This is line four.

如果文本里有空白行,先删除再追加空白行

[root@tzPC 21Unit]# sed '/^$/d ; $!G' data6.txt
This is line one.

This is line two.

This is line three.

This is line four.
[root@tzPC 21Unit]# 

 

删除连续空白行

样本文件data8.txt

[root@tzPC 21Unit]# cat data8.txt
This is line one.


This is line two.

This is line three.



This is line four.

脚本

[root@tzPC 21Unit]# sed '/./,/^$/!d' data8.txt
This is line one.

This is line two.

This is line three.

This is line four.
[root@tzPC 21Unit]# 

区间/./到 /^$/会匹配任意含有至少一个字符的行到空行,在这个区间内的行不会被删除,其他都会被删除。

 

删除开头空白行

样本文件data9.txt

[root@tzPC 21Unit]# cat data9.txt



This is line one.

This is line two.
[root@tzPC 21Unit]# 

脚本

[root@tzPC 21Unit]# sed '/./,$!d' data9.txt
This is line one.

This is line two.
[root@tzPC 21Unit]# 

区间从含有字符的行开始到末尾都不会删除,其他都会删除。

 

删除结尾的空白行

这个例子也理解不了

样本文件data10.txt

[root@tzPC 21Unit]# cat data10.txt
This is the first line.
This is the second line.



[root@tzPC 21Unit]# 

脚本

[root@tzPC 21Unit]# sed '{
> :start
> /^\n*$/{$d ; N ; b start }
> }' data10.txt
This is the first line.
This is the second line.

花括号中的花括号是命令分组,相当于命令中嵌套命令,for中嵌套for

该命令分组应用到指定的地址模式/^\n*$/上,P465,理解不了了,到时候哪天开窍了倒回来看看这个例子。

 

给文件添加行号

解决了我此生最大的疑惑。

[root@tzPC 21Unit]# sed '=' data2.txt
1
This is the header line.
2
This is the first data line.
3
This is the second data line.
4
This is the last line.
[root@tzPC 21Unit]# sed '=' data2.txt | sed 'N; s/\n/ /'
1 This is the header line.
2 This is the first data line.
3 This is the second data line.
4 This is the last line.

nl跟cat -n 命令也能做到

[root@tzPC 21Unit]# nl data2.txt
     1    This is the header line.
     2    This is the first data line.
     3    This is the second data line.
     4    This is the last line.
[root@tzPC 21Unit]# cat -n data2.txt
     1    This is the header line.
     2    This is the first data line.
     3    This is the second data line.
     4    This is the last line.

 

实时打印最后一行

打印最后一行

[root@tzPC 21Unit]# sed -n '$p' data2.txt
This is the last line.

创建滚动窗口的实现思路

使用$检查是否处于末行,如果不是,则向模式空间中增加行同时删除原来的行。

样本文件data7.txt

[root@tzPC 21Unit]# cat data7.txt
This is line 1.
This is line 2.
This is line 3.
This is line 4.
This is line 5.
This is line 6.
This is line 7.
This is line 8.
This is line 9.
This is line 10.

$q如果是最后一行则退出,如果不是则N将下一行添加到模式空间当前行之后,如果当前行在第5行后,6,$D就会删除模式空间的第一行,依次创建出滑动窗口效果。

这个sed脚本胡i显示出data7.txt最后5行。

这个例子也不明白,先放一边。

[root@tzPC 21Unit]# sed '{
:start
$q ; N ; 6,$D
b start
}' data7.txt
This is line 6.
This is line 7.
This is line 8.
This is line 9.
This is line 10.

 

删除HTML标签

样本文件data11.txt

[root@tzPC 21Unit]# cat data11.txt
<html>
<head>
<title>This is the page title</title>
</head>
<body>
<p>
This is the <b>first</b> line in the Web page.
This should provide some <i>useful</i>
information to use in our sed script.
</p>
</body>
</html>

按照常理来写,s/<.*>//g这样会匹配<b>first</b>外围的<>,从而把整个<b>first</b>删除掉。

[root@tzPC 21Unit]# sed 's/<.*>//g' data11.txt






This is the  line in the Web page.
This should provide some 
information to use in our sed script.



[root@tzPC 21Unit]# 

脚本

[root@tzPC 21Unit]# sed 's/<[^>]*>//g ; /^$/d' data11.txt
This is the page title
This is the first line in the Web page.
This should provide some useful
information to use in our sed script.

 

学习来自:《Linux命令行与Shell脚本大全 第3版》第21章

     《Linux运维之道 第2版》第3章

posted @ 2020-08-31 11:01  努力吧阿团  阅读(244)  评论(0编辑  收藏  举报