还是先看sed原理图
什么时候会用到模式空间,那就是在有h,x等命令的时候
g 拷贝资料从 hold space。
G 添加资料从 hold space 至 pattern space 。
h 拷贝资料从 pattern space 至 hold space 。
H 添加资料从 pattern space 至 hold space 。
x 交换 hold space 与 pattern space 内容。
那模式空间和暂存空间他们是如何和谐相处的,或者说,暂存空间的存在可以实现什么功能呢?慢慢看
原理:
$ sed -e '/test/h' -e '$G' example
-----在sed处理文件的时候,每一行都被保存在一个叫模式空间的临时缓冲区中,除非行被删除或者输出被取消,否则所有被处理的行都将打印在屏幕上。接着模式空间被清空,并存入新的一行等待处理。在这个例子里,匹配test的行被找到后,将存入模式空间,h命令将其复制并存入一个称为保持缓存区的特殊缓冲区内。第二条语句的意思是,当到达最后一行后,G命令取出保持缓冲区的行,然后把它放回模式空间中,且追加到现在已经存在于模式空间中的行的末尾。
在这个例子中就是追加到最后一行。简单来说,任何包含test的行都被复制并追加到该文件的末尾。
看下详细的例子把
[root@centos-fuwenchao tmp]# more zckj
PARIS PS1 CHARLES CHIN 01/20/86 30
INDIAN OCEAN PS2 SUSAN GREEN 04/05/86 32
SUST PS2 Lewis Gray 08/11/85 23
JUST IS1 Xiao Ming 11/30/84 9
HEBUT IS1 John Main 12/03/84 8
SUST PS2 Da Ming 06/01/86 35
Paris IS3 PETER Webor 07/05/82 32
Paris PS2 Ann Sreph 09/28/85 10
Paris IS3 Margot Strong 02/29/82 9
--
[root@centos-fuwenchao tmp]# sed -e '/JUST/h' -e '$g' zckj
PARIS PS1 CHARLES CHIN 01/20/86 30
INDIAN OCEAN PS2 SUSAN GREEN 04/05/86 32
SUST PS2 Lewis Gray 08/11/85 23
JUST IS1 Xiao Ming 11/30/84 9
HEBUT IS1 John Main 12/03/84 8
SUST PS2 Da Ming 06/01/86 35
Paris IS3 PETER Webor 07/05/82 32
Paris PS2 Ann Sreph 09/28/85 10
JUST IS1 Xiao Ming 11/30/84 9
解释:我把匹配JUST的行放在暂存空间中,sed接着往下处理,当处理到最后一行的时候,缓存空间和暂存空间互换,所以最后一行输出的是暂存空间的内容
那么H,G和小写的h,g有什么区别呢?
H命令和G命令与h和g命令的唯一不同是H和G是H将模式空间里的内容追加到暂存缓冲区,G将暂存缓冲区里的内容追加到模式空间。
看:
[root@centos-fuwenchao tmp]# sed -e '/JUST/h' -e '$G' zckj
PARIS PS1 CHARLES CHIN 01/20/86 30
INDIAN OCEAN PS2 SUSAN GREEN 04/05/86 32
SUST PS2 Lewis Gray 08/11/85 23
JUST IS1 Xiao Ming 11/30/84 9
HEBUT IS1 John Main 12/03/84 8
SUST PS2 Da Ming 06/01/86 35
Paris IS3 PETER Webor 07/05/82 32
Paris PS2 Ann Sreph 09/28/85 10
Paris IS3 Margot Strong 02/29/82 9
JUST IS1 Xiao Ming 11/30/84 9
解释:原文本的最后一行照常输出了,这是因为大写的G是追加到模式空间,而你不是覆盖!
看:
[root@centos-fuwenchao tmp]# sed -e '/SUST/h' -e '$G' zckj
PARIS PS1 CHARLES CHIN 01/20/86 30
INDIAN OCEAN PS2 SUSAN GREEN 04/05/86 32
SUST PS2 Lewis Gray 08/11/85 23
JUST IS1 Xiao Ming 11/30/84 9
HEBUT IS1 John Main 12/03/84 8
SUST PS2 Da Ming 06/01/86 35
Paris IS3 PETER Webor 07/05/82 32
Paris PS2 Ann Sreph 09/28/85 10
Paris IS3 Margot Strong 02/29/82 9
SUST PS2 Da Ming 06/01/86 35
解释:小写的h是覆盖暂存区,所以给出的最后一行是最后一个匹配的行
看:
[root@centos-fuwenchao tmp]# sed -e '/SUST/h' -e '$g' zckj
PARIS PS1 CHARLES CHIN 01/20/86 30
INDIAN OCEAN PS2 SUSAN GREEN 04/05/86 32
SUST PS2 Lewis Gray 08/11/85 23
JUST IS1 Xiao Ming 11/30/84 9
HEBUT IS1 John Main 12/03/84 8
SUST PS2 Da Ming 06/01/86 35
Paris IS3 PETER Webor 07/05/82 32
Paris PS2 Ann Sreph 09/28/85 10
SUST PS2 Da Ming 06/01/86 35
解释:最后一个匹配的行替换了最后一行
看:
[root@centos-fuwenchao tmp]# sed -e '/SUST/H' -e '$g' zckj
PARIS PS1 CHARLES CHIN 01/20/86 30
INDIAN OCEAN PS2 SUSAN GREEN 04/05/86 32
SUST PS2 Lewis Gray 08/11/85 23
JUST IS1 Xiao Ming 11/30/84 9
HEBUT IS1 John Main 12/03/84 8
SUST PS2 Da Ming 06/01/86 35
Paris IS3 PETER Webor 07/05/82 32
Paris PS2 Ann Sreph 09/28/85 10
SUST PS2 Lewis Gray 08/11/85 23
SUST PS2 Da Ming 06/01/86 35
解释:大些的H追加到暂存区,所以匹配到的两行都保存在暂存区中,替换了原文本的最后一行
看:
[root@centos-fuwenchao tmp]# sed -e '/SUST/H' -e '$G' zckj
PARIS PS1 CHARLES CHIN 01/20/86 30
INDIAN OCEAN PS2 SUSAN GREEN 04/05/86 32
SUST PS2 Lewis Gray 08/11/85 23
JUST IS1 Xiao Ming 11/30/84 9
HEBUT IS1 John Main 12/03/84 8
SUST PS2 Da Ming 06/01/86 35
Paris IS3 PETER Webor 07/05/82 32
Paris PS2 Ann Sreph 09/28/85 10
Paris IS3 Margot Strong 02/29/82 9
SUST PS2 Lewis Gray 08/11/85 23
SUST PS2 Da Ming 06/01/86 35
解释:都是大写,匹配到的追加到最后一行,输出!
写到这里有没有一点奇怪的地方,g或者G前面的$是干嘛用的呀,我也不是很清楚呀,那就接着试验呗
看
[root@centos-fuwenchao tmp]# sed -e '/SUST/H' -e 'G' zckj
PARIS PS1 CHARLES CHIN 01/20/86 30
INDIAN OCEAN PS2 SUSAN GREEN 04/05/86 32
SUST PS2 Lewis Gray 08/11/85 23
SUST PS2 Lewis Gray 08/11/85 23
JUST IS1 Xiao Ming 11/30/84 9
SUST PS2 Lewis Gray 08/11/85 23
HEBUT IS1 John Main 12/03/84 8
SUST PS2 Lewis Gray 08/11/85 23
SUST PS2 Da Ming 06/01/86 35
SUST PS2 Lewis Gray 08/11/85 23
SUST PS2 Da Ming 06/01/86 35
Paris IS3 PETER Webor 07/05/82 32
SUST PS2 Lewis Gray 08/11/85 23
SUST PS2 Da Ming 06/01/86 35
Paris PS2 Ann Sreph 09/28/85 10
SUST PS2 Lewis Gray 08/11/85 23
SUST PS2 Da Ming 06/01/86 35
Paris IS3 Margot Strong 02/29/82 9
SUST PS2 Lewis Gray 08/11/85 23
SUST PS2 Da Ming 06/01/86 35
他是怎么处理的
解释:如果匹配到对应行,则输出,以后每当有行读到缓冲区时候,不仅输出改行,还把暂存区中的行输出,当有第二次匹配是,追加到暂存区,此时暂存区中保留了两行,而这时再从原文件中读入行时,暂存区的内容就被追加到缓存区中输出,只是,原文件中的每一行都会跟这两行匹配的输出项,如此循环
看完上面的,能不能预测如果用小写的h和g的输出呢
预测一:
H & g的输出------>首先原样输出行,当遇到匹配行时,追加到暂存区,读入下一行是,暂存区替换缓存区,所以输出是首先原样,然后一旦遇到匹配行,则输出全是匹配行
[root@centos-fuwenchao tmp]# sed -e '/SUST/H' -e 'g' zckj
SUST PS2 Lewis Gray 08/11/85 23
SUST PS2 Lewis Gray 08/11/85 23
SUST PS2 Lewis Gray 08/11/85 23
SUST PS2 Lewis Gray 08/11/85 23
SUST PS2 Da Ming 06/01/86 35
SUST PS2 Lewis Gray 08/11/85 23
SUST PS2 Da Ming 06/01/86 35
SUST PS2 Lewis Gray 08/11/85 23
SUST PS2 Da Ming 06/01/86 35
SUST PS2 Lewis Gray 08/11/85 23
SUST PS2 Da Ming 06/01/86 35
[root@centos-fuwenchao tmp]#
看来我的预测还是有点错误呀,就是没有遇到匹配行时,原行也是输出匹配行,看来他的处理原理是首先匹配行到暂存区,接着才执行下面的命令!
--更新
现在明白了
他是每一行都要做交换的,第一行是,暂存为空,没有匹配,所以交换的时候第一行为空
第二行同理,
第三行匹配到,追加到暂存,做替换,所以第三行替换为一个空行加上一个原行
第五行第六行同理
第七行有匹配到,追加到暂存,此时暂存为空行+匹配1+匹配2,替换第七行
就这往下同理
所以输出就是上面看到的样子啦
预测二:
h & G 的输出------>每原行都变成 原行+匹配行,遇到的二个匹配行时,每行都是第二个匹配行
[root@centos-fuwenchao tmp]# sed -e '/SUST/h' -e 'G' zckj
PARIS PS1 CHARLES CHIN 01/20/86 30
INDIAN OCEAN PS2 SUSAN GREEN 04/05/86 32
SUST PS2 Lewis Gray 08/11/85 23
SUST PS2 Lewis Gray 08/11/85 23
JUST IS1 Xiao Ming 11/30/84 9
SUST PS2 Lewis Gray 08/11/85 23
HEBUT IS1 John Main 12/03/84 8
SUST PS2 Lewis Gray 08/11/85 23
SUST PS2 Da Ming 06/01/86 35
SUST PS2 Da Ming 06/01/86 35
Paris IS3 PETER Webor 07/05/82 32
SUST PS2 Da Ming 06/01/86 35
Paris PS2 Ann Sreph 09/28/85 10
SUST PS2 Da Ming 06/01/86 35
Paris IS3 Margot Strong 02/29/82 9
SUST PS2 Da Ming 06/01/86 35
还是有点偏差,真不明白了,那就接着再看看有什么发现没有吧!
--更新解释
第一行没有匹配到,暂存空行,缓存第一行,G空第一行后加一个空行
第二行同理
第三行匹配到,往第三行之后在添加一行
接下来就不解释了
那我现在预测小写的h和g就非吹灰之力了把
[root@centos-fuwenchao tmp]# sed -e '/SUST/h' -e 'g' zckj
SUST PS2 Lewis Gray 08/11/85 23
SUST PS2 Lewis Gray 08/11/85 23
SUST PS2 Lewis Gray 08/11/85 23
SUST PS2 Da Ming 06/01/86 35
SUST PS2 Da Ming 06/01/86 35
SUST PS2 Da Ming 06/01/86 35
SUST PS2 Da Ming 06/01/86 35
接着看看 x 的用法吧
x 交换 hold space 与 pattern space 内容。
[root@centos-fuwenchao tmp]# more num.txt
1
2
3
4
5
6
7
8
[root@centos-fuwenchao tmp]# sed -e '/1/h' -e '/8/x' num.txt
1
2
3
4
5
6
7
1
单向替换,这是什么情况!!!!
---更新
sed -e '/test/h' -e '/check/x' example -----互换模式空间和保持缓冲区的内容。也就是把包含test与check的行互换。
解释为什么是单向替换吧!!
首先 找到 模式匹配的 1 ,保存到暂存区,接着执行第二条命令,找到 匹配的 8 ;呵呵。这是暂存区是1 ,缓存区是 8 ,替换之后就是上面的输出结果啦,看起来像是单向匹配;
转念一想,这样是不是也可以呢
[root@centos-fuwenchao tmp]# sed -e '/1/h' -e '/8/g' num.txt
1
2
3
4
5
6
7
1
[root@centos-fuwenchao tmp]# sed -e 's/1/8/' -e 's#8#1#' num.txt
1
2
3
4
5
6
7
1
[root@centos-fuwenchao tmp]#
这样呢
[root@centos-fuwenchao tmp]# sed -e '/1/H' -e '/8/g' num.txt
1
2
3
4
5
6
7
1
[root@centos-fuwenchao tmp]#
(7和1之间有个空行)
写到这我好想明白了点什么!
暂时解决双向替换的问题吧
[root@centos-fuwenchao tmp]# sed -e '/1/H;/8/H' -e '/8/x' num.txt
1
2
3
4
5
6
7
1
8
[root@centos-fuwenchao tmp]# sed -e '/1/H;/8/H' -e '/8/x' num.txt
1
2
3
4
5
6
7
1
8
[root@centos-fuwenchao tmp]# sed -e '/1/h;/8/H' -e '/8/x' num.txt
1
2
3
4
5
6
7
1
8
[root@centos-fuwenchao tmp]# sed -e '/1/h;/8/h' -e '/8/x' num.txt
1
2
3
4
5
6
7
8
[root@centos-fuwenchao tmp]#
写到这,两个命令的执行顺序貌似是先执行第一个,接着执行第二个
但是再看看
[root@centos-fuwenchao tmp]# sed -e '/1/h;/8/H' -e '/5/x' num.txt
1
2
3
4
1
6
7
8
[root@centos-fuwenchao tmp]# sed -e '/1/H;/8/H' -e '/5/x' num.txt
1
2
3
4
1
6
7
8
[root@centos-fuwenchao tmp]#
看到这,你还会以为他是先执行第一个e,在执行第二个e吗?
什么感觉,他是按照匹配的模式交替顺序进行的吗
[root@centos-fuwenchao tmp]# sed -e 's/2/8/' -e 's#1#7#' num.txt
7
8
3
4
5
6
7
8
[root@centos-fuwenchao tmp]#
还会那样认为吗?
再看看
[root@centos-fuwenchao tmp]# sed -e '/1/h' -e '/2/G' num.txt
1
2
1
3
4
5
6
7
8
[root@centos-fuwenchao tmp]# sed -e '/5/h' -e '/1/G' num.txt
1
2
3
4
5
6
7
8
[root@centos-fuwenchao tmp]#
我现在的结论是e是并行逐行处理的,往上验证下行不行
现在是不是了解到逐行的含义了
先执行第一行,执行第一个e,接着第二个e
接着第二行,执行第一个e,接着第二个e
接着往下
好吧,上面就是最终版了!
做几个验证
[root@centos-fuwenchao tmp]# sed -e '/1/h' -e '/2/G' num.txt
1
2
1
3
4
5
6
7
8
[root@centos-fuwenchao tmp]# sed -e '/5/h' -e '/1/G' num.txt
1
2
3
4
5
6
7
8
[root@centos-fuwenchao tmp]# sed -e '/5/h' -e '/1/g' num.txt
2
3
4
5
6
7
8
[root@centos-fuwenchao tmp]# sed -e '/1/h;/8/H' -e '/5/x' num.txt
1
2
3
4
1
6
7
8
[root@centos-fuwenchao tmp]# sed -e '/1/h;/5/H' -e '/6/x' num.txt
1
2
3
4
5
1
5
7
8
[root@centos-fuwenchao tmp]#
碰到这样一个问题
sed -e ’s/72/70/;/@/{h;s/test/next/g;x;G}’ fmt_vuln.c
要解决这个问题,先解决这个问题为什么是这样的吧,为了解释,我用-分割一下
[root@centos-fuwenchao tmp]# sed -e '/1/h;/5/H' -e '/6/x;G' num.txt
1
1
- //匹配到1,缓存1,暂存1,G将暂存1加入缓存1,此时缓存1 1 暂存 1 输出1 1
2
1
- //同理
3
1
- // 同理
4
1
- //同理
5
1
5
- //缓存5 暂存1 5 ;G将1 5 追加入缓存 ,此时缓存 5 1 5
1
5
6
- // 缓存 6 暂存 1 5 ;x将他们互换,此时 缓存 1 5 ,暂存6;G将6追加到缓存 ;此时缓存 1 5 6
7
6
- // 缓存 7 暂存 6 ;G 将6追加到缓存 缓存 7 6
8
6
- //同理
--
[root@centos-fuwenchao tmp]# sed -e 's/7/345/;/8/{h;s/8/888/;x;G}' num.txt
1
2
3
4
5
6
345
8
888
都到这了,那个命令就不解释了吧!
加一点吧
一次执行多个命令的方式有三种:
(1) sed 's/w1/& w2/g; 1/i\words' filename (使用;号把命令隔开,注意前面不加-e参数)
(2) sed -e 'cmd1' -e 'cmd2' filename (使用多个-e参数)
再加一点
下一个:n命令
$ sed '/test/{ n; s/aa/bb/; }' example-----如果test被匹配,则移动到匹配行的下一行,替换这一行的aa,变为bb,并打印该行,然后继续。
{ } 集合有相同位址参数的指令。