一、介绍
sed(流处理编辑器),是Linux下一款功能强大的非交互流式文本编辑器,可以对文本文件进行增、删、改、查等操作,支持按行、按字段、按正则匹配文本内容,灵活方便,特别适合于大文件的编辑。sed在处理文本时是逐行读取文件内容,读到匹配的行就根据指令做操作,不匹配就跳过。处理文本的过程如下:
1、从文本或者管道中读入一行内容到模式空间(临时缓冲区)
2、使用sed命令处理,重复第1步,直到文件处理完毕
3、输出到屏幕
注意两点:
1、sed一次处理一行的内容
2、sed默认的不改变文件内容
*测试数据
[root@localhost test]# cat -n data.txt 1 小红 女 20 BeiJing China 2 小明 男 22 ChongQing China 3 花花 女 30 HeBei China 4 Jane 女 29 Los Angeles America 5 Maecheal 男 30 Washington America 6 山本 男 25 Nagasaki Japan 7 村上春树 男 40 Hiroshima Japan 8 贝爷 男 35 Paris Franch
二、使用sed的格式
- 命令行格式:将包含sed的命令写在命令行中执行
$ sed [options] 'command' files
- 脚本格式:将sed的命令写在一个脚本中,然后执行的时候,指定sed脚本的路径(scriptfile)即可
$ sed -f scriptfile files
上面这两个命令中,files都是要进行处理的文件。
命令行格式
$sed [options] 'command' files
options:
-e:可以指定多个command
-n:与p(print)命令合用时,表示只显示被选中的行,而不是显示所有的行,然后被选中的行会显示两次。
-i:将sed的操作结果更新到文件中,因为默认的是不会操作文件本身的。
-f:后跟保存了sed指令的文件
command:行定位(正则)+ sed命令,首先会通过正则进行行定位,选中要进行操作的行,然后执行sed命令
①行定位:选择一行|多行、不选择某行|某几行、间隔选择
- 选择1行,可以使用两种方式:
1、n; 选中1行,n表示行号
2、/pattern/ 使用正则表达式,注意要包含在/..../之间
[root@localhost test]# #打印第5行 [root@localhost test]# sed -n "5 p" data.txt Maecheal 男 30 Washington America [root@localhost test]# #打印匹配"China"的记录 [root@localhost test]# sed -n "/china/ p" data.txt [root@localhost test]# sed -n "/China/ p" data.txt 小红 女 20 BeiJing China 小明 男 22 ChongQing China 花花 女 30 HeBei China
- 选择多行,同样有两种方式:
1、x,y; 选中行号在x~y之间的行
2、/pattern1/, /pattern2/ 选择匹配两个正则表达式之间的行
[root@localhost test]# #打印第3~6行 [root@localhost test]# cat -n data.txt | sed -n "3,6 p" 3 花花 女 30 HeBei China 4 Jane 女 29 Los Angeles America 5 Maecheal 男 30 Washington America 6 山本 男 25 Nagasaki Japan [root@localhost test]# #打印“Jane”的行,到“贝爷”之间的行 [root@localhost test]# sed -n "/Jane/, /贝爷/ p" data.txt Jane 女 29 Los Angeles America Maecheal 男 30 Washington America 山本 男 25 Nagasaki Japan 村上春树 男 40 Hiroshima Japan 贝爷 男 35 Paris Franch
- 不选择某一行或者某几行
在后面加 ! 即可
[root@localhost test]# #打印除了第4行以外的所有行 [root@localhost test]# cat -n data.txt | sed -n "4! p" 1 小红 女 20 BeiJing China 2 小明 男 22 ChongQing China 3 花花 女 30 HeBei China 5 Maecheal 男 30 Washington America 6 山本 男 25 Nagasaki Japan 7 村上春树 男 40 Hiroshima Japan 8 贝爷 男 35 Paris Franch [root@localhost test]# #打印除3-7行之外的行 [root@localhost test]# cat -n data.txt | sed -n "3,7! p" 1 小红 女 20 BeiJing China 2 小明 男 22 ChongQing China 8 贝爷 男 35 Paris Franch
- 间隔几行选择
使用x~y格式,首先打印第x行,然后每个y行,就打印一次
[root@localhost test]# #打印第3行,之后,每隔2行,就打印一次 [root@localhost test]# cat -n data.txt | sed -n "3~2 p" 3 花花 女 30 HeBei China 5 Maecheal 男 30 Washington America 7 村上春树 男 40 Hiroshima Japan
②操作命令
sed有几个基本的操作命令,分别是下面几个:
1、-a (append,添加,在行后追加)
2、-i(insert,插入,在行前插入)
3、-d(delete,删除行)
4、-c(chage,替换)
5、-s(subsitute,替换)
6、-p(打印 打印出匹配的内容,通常与-n选项合用)
7、-n(读取下一行,遇到n时会自动跳入下一行)
8、-r,w(读和写编辑命令,r用于将内容读入文件,w用于将匹配内容写入到文件)
9、&表示前面已经匹配的字符串内容,反向引用,不用再写一次正则表达式
10、{command1; command2; command 3}多个sed命令,使用“;”分开
-a 增加行
[root@localhost test]# #在第3行后面增加一行“---------------” [root@localhost test]# cat -n data.txt | sed "3a -------------" 1 小红 女 20 BeiJing China 2 小明 男 22 ChongQing China 3 花花 女 30 HeBei China ------------- 4 Jane 女 29 Los Angeles America 5 Maecheal 男 30 Washington America 6 山本 男 25 Nagasaki Japan 7 村上春树 男 40 Hiroshima Japan 8 贝爷 男 35 Paris Franch [root@localhost test]# #在3~5行的每一行后面加一行“==========” [root@localhost test]# cat -n data.txt | sed "3,5a ==========" 1 小红 女 20 BeiJing China 2 小明 男 22 ChongQing China 3 花花 女 30 HeBei China ========== 4 Jane 女 29 Los Angeles America ========== 5 Maecheal 男 30 Washington America ========== 6 山本 男 25 Nagasaki Japan 7 村上春树 男 40 Hiroshima Japan 8 贝爷 男 35 Paris Franch [root@localhost test]# #在每一行后面增加一行“===========” [root@localhost test]# cat -n data.txt | sed "a ==========" 1 小红 女 20 BeiJing China ========== 2 小明 男 22 ChongQing China ========== 3 花花 女 30 HeBei China ========== 4 Jane 女 29 Los Angeles America ========== 5 Maecheal 男 30 Washington America ========== 6 山本 男 25 Nagasaki Japan ========== 7 村上春树 男 40 Hiroshima Japan ========== 8 贝爷 男 35 Paris Franch ========== [root@localhost test]# #在行末增加一行“-------------------” [root@localhost test]# sed '$a -------------------------' data.txt 小红 女 20 BeiJing China 小明 男 22 ChongQing China 花花 女 30 HeBei China Jane 女 29 Los Angeles America Maecheal 男 30 Washington America 山本 男 25 Nagasaki Japan 村上春树 男 40 Hiroshima Japan 贝爷 男 35 Paris Franch -------------------------
-i 插入行:-i插入行和增加行的操作一样,区别是a是在行之后增加,i是在行之前插入
[root@localhost test]# #在第3行之前增加一行“---------------” [root@localhost test]# cat -n data.txt | sed "3i --------------" 1 小红 女 20 BeiJing China 2 小明 男 22 ChongQing China -------------- 3 花花 女 30 HeBei China 4 Jane 女 29 Los Angeles America 5 Maecheal 男 30 Washington America 6 山本 男 25 Nagasaki Japan 7 村上春树 男 40 Hiroshima Japan 8 贝爷 男 35 Paris Franch [root@localhost test]# #在第3~5行的每一行之前插入一行"===========" [root@localhost test]# cat -n data.txt | sed "3,5i ===========" 1 小红 女 20 BeiJing China 2 小明 男 22 ChongQing China =========== 3 花花 女 30 HeBei China =========== 4 Jane 女 29 Los Angeles America =========== 5 Maecheal 男 30 Washington America 6 山本 男 25 Nagasaki Japan 7 村上春树 男 40 Hiroshima Japan 8 贝爷 男 35 Paris Franch [root@localhost test]# #在每一行之前插入一行"===========" [root@localhost test]# cat -n data.txt | sed "i ===========" =========== 1 小红 女 20 BeiJing China =========== 2 小明 男 22 ChongQing China =========== 3 花花 女 30 HeBei China =========== 4 Jane 女 29 Los Angeles America =========== 5 Maecheal 男 30 Washington America =========== 6 山本 男 25 Nagasaki Japan =========== 7 村上春树 男 40 Hiroshima Japan =========== 8 贝爷 男 35 Paris Franch
-c 替换行
替换行,是指将指定行整行内容都替换为指定内容,注意-s是指替换行中的一部分内容。
注意,区间替换的时候,是整体替换,而不是逐行替换。
[root@localhost test]# #将第2行替换为"hello shell" [root@localhost test]# cat -n data.txt | sed "2c hello world" 1 小红 女 20 BeiJing China hello world 3 花花 女 30 HeBei China 4 Jane 女 29 Los Angeles America 5 Maecheal 男 30 Washington America 6 山本 男 25 Nagasaki Japan 7 村上春树 男 40 Hiroshima Japan 8 贝爷 男 35 Paris Franch [root@localhost test]# #尝试将第2~5行的每一行都替换为"hello world",但是实际操作后会将2-5行整体替换 [root@localhost test]# cat -n data.txt | sed "2,5c hello world" 1 小红 女 20 BeiJing China hello world 6 山本 男 25 Nagasaki Japan 7 村上春树 男 40 Hiroshima Japan 8 贝爷 男 35 Paris Franch [root@localhost test]# #将每一行都替换为“hello world” [root@localhost test]# cat -n data.txt | sed "c hello world" hello world hello world hello world hello world hello world hello world hello world hello world
-d 删除行
[root@localhost test]# #删除第4行 [root@localhost test]# cat -n data.txt | sed "4d" 1 小红 女 20 BeiJing China 2 小明 男 22 ChongQing China 3 花花 女 30 HeBei China 5 Maecheal 男 30 Washington America 6 山本 男 25 Nagasaki Japan 7 村上春树 男 40 Hiroshima Japan 8 贝爷 男 35 Paris Franch [root@localhost test]# #删除第4-6行 [root@localhost test]# cat -n data.txt | sed "4,6d" 1 小红 女 20 BeiJing China 2 小明 男 22 ChongQing China 3 花花 女 30 HeBei China 7 村上春树 男 40 Hiroshima Japan 8 贝爷 男 35 Paris Franch [root@localhost test]# #删除所有行(无意义) [root@localhost test]# cat -n data.txt | sed 'd'
-s 替换行的部分内容
[root@localhost test]# #将字符a替换为X [root@localhost test]# sed 's/a/X/' data.txt 小红 女 20 BeiJing ChinX 小明 男 22 ChongQing ChinX 花花 女 30 HeBei ChinX JXne 女 29 Los Angeles America MXecheal 男 30 Washington America 山本 男 25 NXgasaki Japan 村上春树 男 40 HiroshimX Japan 贝爷 男 35 PXris Franch
注意,在替换的时候,只替换了一次,即只替换第一个匹配的内容。如果要将满足条件的内容都替换,就需要加上g
[root@localhost test]# sed 's/a/X/g' data.txt 小红 女 20 BeiJing ChinX 小明 男 22 ChongQing ChinX 花花 女 30 HeBei ChinX JXne 女 29 Los Angeles AmericX MXecheXl 男 30 WXshington AmericX 山本 男 25 NXgXsXki JXpXn 村上春树 男 40 HiroshimX JXpXn 贝爷 男 35 PXris FrXnch
多个sed命令
使用花括号{ }将多个sed命令包含在一起,多个sed之间用;分开
[root@localhost test]# cat -n data.txt 1 小红 女 20 BeiJing China 2 小明 男 22 ChongQing China 3 花花 女 30 HeBei China 4 Jane 女 29 Los Angeles America 5 Maecheal 男 30 Washington America 6 山本 男 25 Nagasaki Japan 7 村上春树 男 40 Hiroshima Japan 8 贝爷 男 35 Paris Franch [root@localhost test]# cat -n data.txt | sed '{3,5 d; s/China/Chinese/}' 1 小红 女 20 BeiJing Chinese 2 小明 男 22 ChongQing Chinese 6 山本 男 25 Nagasaki Japan 7 村上春树 男 40 Hiroshima Japan 8 贝爷 男 35 Paris Franch
&反向引用
&表示前面已经匹配的字符串内容,反向引用,不用再写一次正则表达式
在男或者女之前加一个gender单词
[root@localhost test]# cat -n data.txt | sed 's/[男|女]/gender:[男|女]/' 1 小红 gender:[男|女] 20 BeiJing China 2 小明 gender:[男|女] 22 ChongQing China 3 花花 gender:[男|女] 30 HeBei China 4 Jane gender:[男|女] 29 Los Angeles America 5 Maecheal gender:[男|女] 30 Washington America 6 山本 gender:[男|女] 25 Nagasaki Japan 7 村上春树 gender:[男|女] 40 Hiroshima Japan 8 贝爷 gender:[男|女] 35 Paris Franch [root@localhost test]# cat -n data.txt | sed 's/[男|女]/gender:&/' 1 小红 gender:女 20 BeiJing China 2 小明 gender:男 22 ChongQing China 3 花花 gender:女 30 HeBei China 4 Jane gender:女 29 Los Angeles America 5 Maecheal gender:男 30 Washington America 6 山本 gender:男 25 Nagasaki Japan 7 村上春树 gender:男 40 Hiroshima Japan 8 贝爷 gender:男 35 Paris Franch
三、模式空间和保持空间
1.sed 有两个内置的存储空间:
- 模式空间:模式空间用于 sed 执行的正常流程中。该空间 sed 内置的一个缓冲区,用来存放、修改从输入文件读取的内容。
- 保持空间:保持空间是另外一个缓冲区,用来存放临时数据。
Sed 可以在保持空间和模式空间交换数据,但是不能在保持空间上执行普通的 sed 命令。每次循环读取数据过程中,模式空间的内容都会被清空,然而保持空间的内容则保持不变,不会在循环中被删除。模式空间可以比喻为一个生产线,而保持空间则可以被比喻为仓库。
2.sed中关于模式空间(P)和保持空间(M)的常见指令
h:把模式空间里的内容复制到保持空间 H:把模式空间里的内容追加到保持空间 g:把保持空间里的内容复制到模式空间,覆盖原有的内容 G:把保持空间的内容追加到模式空间里,追加在原有内容的后面 n:提前读取下一行,覆盖模型空间前一行,然后执行后续命令。然后再读取新行,对新读取的内容重头执行sed N:追加下一行到模式空间,同时将两行看做一行,但是两行之间依然含有 换行符,然后执行后续命令。然后再读取新行,对新读取的内容重头执行sed。此时,新读取的行会覆盖之前的行(之前的两行已经合并为一行) p:p打印当前模式空间所有内容,追加到默认输出之后 P:打印当前模式空间开端至 的内容,并追加到默认输出之前。 d:删除模式空间的内容,然后读取下一行到空间,并且忽略后边的命令,进行新一次的循环 D:删除模式空间的第一行,不读取下一行,忽略后边的命令,在当前空间从头执行命令 x:交换保持空间和模式空间的内容
- h命令 模式空间复制到保持空间
[root@tyler temp]# cat empname.txt John Doe CEO Jason Smith IT Manager Raj Reddy Sysadmin Anand Ram Developer Jane Miller Sales Manager [root@tyler temp]# sed -n -e '/Manager/!h' -e'/Manager/{x;p}' empname.txt Jason Smith Jane Miller [root@tyler temp]# 逐行的读取,'/Manager/!h'表示遇到不包含Manager关键字的行,就复制到保持空间(注意是覆盖了保持空间原有的内容),'/Manager/{x;p}'表示遇到包含Manager关键字的一行,就与保持空间交换并打印交换后的模式空间内容(打印内容就是Manager的上一行)。
- H命令 模式空间追加到保持空间
### 同时管理者姓名和职位 [root@tyler temp]# sed -n '/Manager/!h;/Manager/{H;x;p}' empname.txt Jason Smith IT Manager Jane Miller Sales Manager [root@tyler temp]# 逐行的读取,'/Manager/!h'表示遇到不包含Manager关键字的行,就复制到保持空间(注意是覆盖了保持空间原有的内容),'/Manager/{H;x;p}'表示遇到包含Manager关键字的一行,将模式空间的内容追加到保持空间,此时保持空间中包含Manager及其上一行,x再将保持空间的内容交换到模式空间中,打印输出。 ### 格式化为一行 [root@tyler temp]# sed -n '/Manager/!h;/Manager/{H;x;s/ /: /p}' empname.txt Jason Smith: IT Manager Jane Miller: Sales Manager [root@tyler temp]# 在上一个命令基础上,保持空间中包含Manager及其上一行的内容交换到模式空间中,将换行符换成:后输出。
- g命令 保持空间复制到模式空间
### 打印管理者的姓名 [root@tyler temp]# sed -n '/Manager/!h;/Manager/{g;p}' empname.txt Jason Smith Jane Miller [root@tyler temp]#
- G命令 保持空间追加到模式空间
### 格式打印管理者及其职位 [root@tyler temp]# sed -n '/Manager/!h;/Manager/{x;G;s/ /: /p}' empname.txt Jason Smith: IT Manager Jane Miller: Sales Manager [root@tyler temp]# m代表模式空间,h表示保持空间 先交换(m中为姓名,h为职位),再h追加到m中(m中姓名和职位分行排列),最后替换换行符
- n命令 提前读取下一行,覆盖模型空间前一行,然后执行后续命令。然后再读取新行,对新读取的内容重头执行sed。
从aaa文件中取出偶数行 [root@localhost ~]# cat a.txt This is 1 This is 2 This is 3 This is 4 This is 5 [root@localhost ~]# sed –n ‘n;p’ a.txt This is 2 This is 4 读取This is 1,执行n命令,此时模式空间为This is 2,执行p,打印模式空间内容This is 2,之后读取This is 3,执行n命令,此时模式空间为This is 4,执行p,打印模式空间内容This is 4,之后读取This is 5,执行n命令,因为没有了,所以退出,并放弃p命令。因此,最终打印出来的就是偶数行。
- N命令 追加下一行到模式空间,同时将两行看做一行,但是两行之间依然含有
换行符,然后执行后续命令。然后再读取新行,对新读取的内容重头执行sed。此时,新读取的行会覆盖之前的行(之前的两行已经合并为一行)。
#例子:从aaa文件中读取奇数行 [root@localhost ~]# sed –n ‘N;P’ a.txt -----因为读取第5行时,执行N,发现没有第6行,不满足,就退出,放弃P命令 This is 1 This is 3 [root@localhost ~]# sed –n ‘$!N;P’ a.txt This is 1 This is 3 This is 5 [root@localhost ~]# 注释中1代表This is 1 2代表This is 2 以此类推 注释:读取1,$!条件满足(不是尾行),执行N命令,得出1 2,执>行P,打印得1,读取3,$!条件满足(不是尾行),执行N命令,得出>3 4,执行P,打印得3,读取5,$!条件不满足,跳过N,执行P,打印得5
- d命令 删除当前模式空间内容(不再传至标准输出),并放弃之后的命令,并对新读取的内容,重头执行sed。
[root@localhost ~]# sed ‘n;d’ a.txt This is 1 This is 3 This is 5 [root@localhost ~]# 注释:读取1,执行n,得出2,执行d,删除2,得空,以此类推,读取3,执行n,得出4,执行d,删除4,得空,但是读取5时,因为n无法执行,所以d不执行。因无-n参数,故输出1 3 5
- D命令 删除当前模式空间开端至
的内容(不在传至标准输出),放弃之后的命令,但是对剩余模式空间重新执行sed。
[root@localhost ~]# Sed 'N;D' aaa This is 5 注释:读取1,执行N,得出1 2,执行D,得出2,执行N,得出2 3,执行D,得出3,依此类推,得出5,执行N,条件失败退出,因无-n参数,故输出5
- x命令 将当前缓存区和模式空间内容互换
[root@wmsvmpc ~]# sed –e ‘/101/h’ –e ‘/102/x’ cs1.txt PBCSPOFT0101 6 PBCSPOFT0101 6 PBCSPOFT0103 8 PBCSPOFT0104 0 #互换模式空间和保持缓冲区的内容。也就是把包含101与102的行互换。应该是替换. [root@wmsvmpc ~]# echo –e "a b c d "|sed –nr 'H;${x;s/ //g;p}' abcd r:use extended regular expressions in the script,使用功能更强大的正则表达式。 ${} 表示处理到文件最后一行时执行{}中的命令,x把之前存入缓存区的数据按先入先出的顺序放入模式空间,然后做替换,最后打印
https://blog.csdn.net/kakane/article/details/7367133