文章目录
1模式空间(pattern Space)
sed高级命令分为三部分
- 处理多行模式空间(N, D, P)
- 采用保持空间来保持模式空间的内容并使他可以用于后续的内容(H, h, G, g, x)
- 编写使用条件分支和指令的脚本来更改控制流(:, b, t)
1.1 模式空间的原理
sed是允许一次处理多行的。这就是所谓的多行模式空间
sed不是在原输入上直接进行处理的,而是先将读入的行放到缓冲区中,对缓冲区里的内容进行处理,处理完毕后也不会写回原文件(除非用shell的输出重定向来保存结果),而是直接输出到屏幕上。sed运行过程中维护着两个缓冲区,一个是活动的“模式空间(pattern space)”,另一个是起辅助作用的“保持空间(holding space)”。一般情况下,每当运行sed,sed首先把第一行装入模式空间,进行处理后输出到屏幕,然后将第二行装入模式空间替换掉模式空间里原来的内容,然后进行处理,以此类推
简单来说就是
- sed每当处理一行时,把当前处理的行存储在临时缓冲区中,称为模式空间(Pattern Space)
- 接着用sed命令处理缓冲区中的内容,处理完成后,把缓冲区的内容送往屏幕。接着处理下一行,这样不断重复,直到文件末尾
sed 包含了三个可用来处理多行文本的特殊命令
- Next 命令(N):将数据流中的下一行加进来创建一个多行组来处理
- Delete(D):删除多行组中的一行
- Print(P):打印多行组中的一行
1.2 追加下一行 N(Next)
多行Next (N)命令通过读取新的输入行,并将它添加到模式空间的现有内容之后来创建多行模式空间。模式空间最初的内容和新的输入行之间用换行符分隔。在模式空间中嵌入的换行符可以利用转义序列“\n”来匹配。在多行模式空间中,元字符“^”匹配空间中的第一个字条,而不匹配换行符后面的字符。同样,“$”只匹配模式空间中最后的换行符,而不匹配任何嵌入的换行符。在执行next命令之后,控制将被传递给脚本中的后续命令
-
Next命令与next命令不同,next输出模式空间的内容,然后读取新的输入行。简单来说就是提前读取下一行,覆盖模型空间前一行(并没有删除,因此依然打印至标准输出),如果命令未执行成功(并非跳过:前端条件不匹配),则放弃之后的任何命令,并对新读取的内容,重头执行sed,next命令不创建多行模式空间。
-
N命令简单来说就是追加下一行到模式空间,同时将两行看做一行,但是两行之间依然含有\n换行符,如果命令未执行成功(并非跳过:前端条件不匹配),则放弃之后任何命令,并对新读取的内容,重头执行sed
[root@node2 ~]# cat run
hell
o worl
d tom
[root@node2 ~]# sed '/hell/N;s/\n//' run
hello worl
d tom
[root@node2 ~]# cat sedscr
/hell/{
N;s/\n//
N;s/\n //
}
[root@node2 ~]# sed -f sedscr run
hello world tom
1.3 多行删除 D(Delete)
删除命令(d)删除模式空间的内容并导致读入新的输入行,从而在脚本的顶端重新使用编辑方法。删除命令(D)稍微有些不同:它删除模式空间中直到第一个嵌入的换行符的这部分内容。它不会导致读入新的输入行,相反,它返回到脚本的顶端,将这些指令应用于模式空间剩余的内容,我们可以编写一个实现查找一系列空行并输出单个空行的脚本,以看看它们之间的区别。下面的语句使用了删除命令(d)
- d命令是删除当前模式空间内容(不在传至标准输出),并放弃之后的命令,并对新读取的内容,重头执行sed
//从run文件中取出奇数行
[root@node2 ~]# cat run
This is a
This is b
This is c
This is d
This is e
[root@node2 ~]# sed 'n;d' run
This is a
This is c
This is e
// 读取1,执行n,得出2,执行d,删除2,得空,
以此类推,读取3,执行n,得出4,执行d,删除4,得空,
但是读取5时,因为n无法执行,所以d不执行。因无-n参数,故输出1\n3\n5
当有偶数个空行时,所有的空行都会被删除。仅当有奇数个空行时,有一行被保留下来。这是因为删除命令清除的是整个模式空间。一旦遇到第一个空行,就读入下一行,并且两行都被删除。如果遇到第三个空行,并且下一行不为空,那么删除命令就不会被执行,因此空行被输出。如果使用多行Delete命令(是D不是d),就能得到我们想要的结果:
- D命令是删除当前模式空间开端至\n的内容(不在传至标准输出)即模式空间中的第一行,放弃之后的命令,但是对剩余模式空间(第二行内容)重新执行sed
// 从run文件中读取最后一行
[root@node2 ~]# cat run
This is a
This is b
This is c
This is d
This is e
[root@node2 ~]# sed 'N;D' run
This is e
// 读取1,执行N,得出1\n2,执行D,得出2,执行N,得出2\n3,执行D,得出3,
依此类推,得出5,执行N,条件失败退出,因无-n参数,故输出5
多行Delete命令完成工作的原因是,当遇到两个空行时,Delete命令只删除两个空行中的第一个。下一次遍历该脚本时,这个空行将导致另一行被读入模式空间。如果那行不为空,那么两行都输出,因此确保了输出一个空行。换句话说,当模式空间中有两个空行时、只有第一个空行被删除。当一个空行后面跟有文本时,模式空间可以正常输出。
1.4 多行打印 P(Print)
多行打印(Print),该命令输出多行模式空间的第一部分,直到第一个嵌入的换行符为止,在执行完脚本的最后一个命令之后,模式空间的内容自动输出。
通过下面的例子来学习多行打印的P命令
[root@node2 ~]# cat test
here are examples of the unix
system. where unix
system appears,it should be the unix
operating system
[root@node2 ~]# cat jj
/unix$/{
N
/\nsystem/{
s// operating &/
P
D
}
}
[root@node2 ~]# sed -f jj test
here are examples of the unix operating
system. where unix operating
system appears,it should be the unix
operating system
这里我们要匹配unix结尾的行,并且如果下一行是system,那么在unix之后加上operating
注意: 在sed中,&意思是用正则表达式的内容替换掉读入的内容。另外,//之间不加任何内容,表示的是上一次的匹配。在这例子中就是\nsystem
命令的执行过程如下:
首先读入一行。如果结尾匹配unix,那么读入下一行
- 如果下一行以system开头,那么将system替换成 operating \nsystem,然后打印出来该替换之后的行并把原来的 行删除
- 如果下一行不是system开头,那么以改行为输入,继续匹配是否以unix结尾
2 保持空间(hold space)
- sed 中除了模式空间,还另外还支持保持空间(Hold Space)
- 利用此空间,可以将模式空间中的数据,临时保存至保持空间
- 从而后续接着处理,实现更为强大的功能
- 模式空间可以理解为前台,保持空间可以理解为后台
2.1 什么是保持空间
保持空间是另外一个缓冲区,用来存放临时数据。Sed 可以在保持空间和模式空间交换数据,但是不能在保持空间上执行普通的 sed 命令。我们已经讨论过,每次循环读取数据过程中,模式空间的内容都会被清空,然而保持空间的内容则保持不变,不会在循环中被删除
保持空间的用途: 当改变模式空间中的原始文件时,用于保留当前输入行的副本
2.2 保持空间的原理
- 将第一行放到保留空间中
- 将文本的下一行放到模式空间中
- 将保留空间最佳到模式空间中
- 将模式空间放到保留空间
- 重复第2步到第4步,直至将所有行以相反的顺序放到保留空间。
- 检索行并打印它们。
保留空间常用的命令
命令 | 功能 |
---|---|
h或H | 将模式空间的内容复制或追加到保持空间 |
g或G | 将保存空间的内容复制或追加到模式空间 |
x | 交换保持空间或模式空间的内容 |
实例
// 复制模式空间内容到保持空间,删除模式空间,将保持空间的内容追加到模式空间中输出
[root@node2 ~]# cat time
1
2
11
22
111
222
[root@node2 ~]# sed '/1/{h;d};/2/{G}' time
2
1
22
11
222
111
// 复制模式空间内容到保持空间,在将匹配到模式空间的内容追加到保持空间中。然后将保持空间的内容覆盖到模式空间中输出
[root@node2 ~]# cat time
1
2
11
22
111
222
[root@node2 ~]# sed '/1/{h};/2/{H;g}' time
1
1
2
11
11
22
111
111
222
// 匹配the和statement中间内容将其复制到保持空间中,然后输出中间匹配的内容
[root@node2 ~]# cat time
find the Match statement jjkk
find the tom statement jjkk
[root@node2 ~]# cat jj
/the .* statement/{
h
s/.*the (.*) statement.*/\1/
}
[root@node2 ~]# sed -rf jj time
Match
tom
[root@node2 ~]# cat time
find the Match statement jjkk
find the tom statement jjkk
[root@node2 ~]# cat jj
/the .* statement/{
h
s/.*the (.*) statement.*/\1/ 替换命令行中提取语句的名字,并用它代替整行
y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/ 转换命令将小写字母转换为大写字母
G
s/(.*)\n(.*the ).*( statement.*)/\2\1\3/
}
[root@node2 ~]# sed -rf jj time
find the MATCH statement jjkk
find the TOM statement jjkk
3 高级的流控制命令
之前我们学习了一些改变sed的正常流控制的实例。接下来我们要用到的是用于控制执行脚本的那一部分以及何时执行的命令,分支(b)和测试(t)。这两条命令将脚本中的控制转移到包含特殊标签的行。如果没有指定标签,则将控制转移到脚本的结尾处。分支命令用于无条件转移,测式命令用于有条件转移,它们只有当替换命令改变当前行时才会执行。
标签:任意的字符组合且长度不大于7,它本身占据一行且以冒号开头
:mylabel
冒号和标签之间不能有空格,标签后的空格会被当做标签的一部分
标签和命令之间允许有空格
3.1 分支(b)
b ( branch),在脚本中将控制权转到另一行,通过它你可以跳到你想去的地方,它可以将一组命令当做一个过程来执行且这个过程在脚本中可以重复执行,只要条件满足。
语法:[address]b [label]
address:决定在哪行或哪些行执行分支命令
label:参数定义于何处分支
需要注意的是,如果没有加 label 参数,跳转命令会跳转到脚本的结尾
[root@node2 ~]# cat time
This is the header line.
This is a data line.
This is the lastline.
[root@node2 ~]# sed '{
2,3b 跳过2,3两行
s/This is/Is this/
s/line./test?/
}' time
Is this the header test?
This is a data line.
Is this the lasttest?
因为 b 命令未指定 label 参数,因此数据流中的第2行和第3行并没有执行那两个替换命令
//文本行中出现了 first,程序的执行会直接跳到 jump1 标签之后的脚本行。如果分支命令的模式没有匹配,sed 会继续执行所有的脚本命令
[root@node2 ~]# cat time
This is the header line.
This is the first data line.
This is a second data line.
This is the last line.
[root@node2 ~]# sed '{/first/bjump1;s/This is the/NO jump on/
> :jump1
> s/This is the/Jump here on/}' time
NO jump on header line.
Jump here on first data line.
This is a second data line.
NO jump on last line.
3.2 测试(t)
类似于 b 分支命令,t 命令也可以用来改变 sed 脚本的执行流程。t 测试命令会根据 s 替换命令的结果,如果匹配并替换成功,则脚本的执行会跳转到指定的标签;反之,t 命令无效
语法:[address]t [label]
在没有指定标签的情况下,如果 s 命令替换成功,sed 会跳转到脚本的结尾(相当于不执行任何脚本命令)如下
[root@node2 ~]# cat time
This is the header line.
This is the first data line.
This is a second data line.
This is the last line.
[root@node2 ~]# sed '{
> s/first/matched/
> t
> s/This is the/NO match on/
> }' time
NO match on header line.
This is the matched data line.
This is a second data line.
NO match on last line.
第一个替换命令会查找模式文本 first,如果匹配并替换成功,命令会直接跳过后面的替换命令;反之,如果第一个替换命令未能匹配成功,第二个替换命令就会被执行
例如
[root@node2 ~]# 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.