Linux笔记 三剑客之sed

一、介绍
 
  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
 
 
 
原文地址:https://www.cnblogs.com/dumpling-z/p/11277882.html