Linux教程——sed编辑器使用实例

sed编辑器

前言

在编写脚本文件时,经常需要对文件进行操作,然而vim编辑器却是一款交互式的编辑器,我们无法将其应用到脚本上,而echo配置定向符只能新增文件内容,不能进行修改的操作,这时候sed编辑器配合正则表达式就显得尤为重要了,本篇主要介绍sed编辑器的工作原理以及sed编辑器的常用选项和正则表达式的结合的应用实例,通过大量的命令实例来对sed进行深入的了解。
当然,还是欢迎各路大神前来批评指教的。

sed编辑器概念

流编辑器,是一种非交互式的编辑器,常用于脚本书写。

sed编辑器可以根据输入的命令行的命令或存储在文件中的命令处理数据。它,每次从输入读取一行数据,将该数据所提供的编辑器命令匹配,根据命令修改数据流中的数据,然后将新数据输出到STDOUT。在流编辑器将全部命令和一行数据匹配完之后,它读取下一行数据,并重复上述过程。处理完数据流中的全部数据行之后,该编辑器停止。

sed常用选项

  • -n:屏蔽默认输出(全部文本)
  • -i:直接修改文件内容
  • -f:使用sed脚本
  • -e:可指定多个处理动作
  • -r:启用扩展的正则表达式,若与其他选项一起使用,应作为首个选项
  • {}:可组合多个命令,以分号分隔

这里需要说明的一点有:这里的命令选项和下面的操作命令,两者是相互独立,是不同的两个部分,由于出现了相同字母的部分,所以请注意,别混淆了。

sed基本操作

下面的每一个命令都可以配合正则表达式进行操作,
在sed中使用正则表达式的格式是:‘/正则表达式/命令 [参数]’

这里使用单引号或者双引号都可以,只需要注意单引号屏蔽元字符的效果即可。

‘/IPADDR/p’
‘/line/c change line’
’s/>.*</>test</‘

打印命令

由于sed 默认会有输出,所以当使用-p选项时,会出现每一行的信息会出现两次
可以添加 -n 选项可以禁止其他所有行,即屏蔽默认输出

[root@service99 Sed]# sed 'p' sed_test.txt 
root:x:0:0:root:/root:/bin/bash
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
bin:x:1:1:bin:/bin:/sbin/nologin
[root@service99 Sed]# sed -n 'p' sed_test.txt 
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin

其他使用实例

[root@service99 Sed]# cat test.info 
DEVICE=eth1
TYPE=Ethernet
ONBOOT=yes
BOOTPROTO=none
IPV6INIT=no
USERCTL=no
IPADDR=192.168.2.99
PREFIX=24
[root@service99 Sed]# sed -n '1p' test.info  //查看第一行内容
DEVICE=eth1
[root@service99 Sed]# sed -n '1,3p' test.info  //查看第一,三行内容
DEVICE=eth1
TYPE=Ethernet
ONBOOT=yes
[root@service99 Sed]# sed -n '1~2p' test.info  //查看从第一行开始步数为2的查看文件内容,此例情况即是1,3行内容
DEVICE=eth1
ONBOOT=yes
IPV6INIT=no
IPADDR=192.168.2.99

对于sed中行号的说明,其实就是单纯的使用“1”“1,3”“1~3”,上述的命令只是列举,其他指令也是类似的。

在这一部分我们还可以与正则表达式进行配合使用,‘/正则表达式/p’。

[root@service99 Sed]# sed -n '/root/p' sed_test.txt 
root:x:0:0:root:/root:/bin/bash
operator:x:11:0:operator:/root:/sbin/nologin
[root@service99 Sed]# sed -n '/ro*/p' sed_test.txt 
root:x:0:0:root:/root:/bin/bash
adm:x:3:4:adm:/var/adm:/sbin/nologin

sed文本替换

在进行文本替换这一块,可以说sed1的这一功能也许是用的最多的,因为很多配置文件的修改都需要进行该功能,然而想要替换文本,那么首先我们需要找到的要修改的文本,说到了查找那就需要使用正则表达式了。

sed文本替换命令格式:
sed ‘s/原内容/替换内容/[替换标记]’

在原内容的地方,我们可以使用正则表达式来匹配文本,也可以直接输入替换文本。
不过由于正则表达式中就有一个单词匹配的功能,那么也就可以直接理解为就是使用正则表达式。

[root@service99 Sed]# cat replace_test.txt 
2016 2017 2016 end1
asdf 2016 test bind
name 2016 2016 tftp
2016 2016 2016 2016
2017 2017 0000 ssss
[root@service99 Sed]# sed 's/2016/2017/' replace_test.txt 
2017 2017 2016 end1
asdf 2017 test bind
name 2017 2016 tftp
2017 2016 2016 2016
2017 2017 0000 ssss
[root@service99 Sed]# sed 's/end1/END1/' replace_test.txt 
2016 2017 2016 END1
asdf 2016 test bind
name 2016 2016 tftp
2016 2016 2016 2016
2017 2017 0000 ssss

替换命令在替换多个文本行中的文本效果不错,但是你们也发现了,
默认情况下仅替换各行中首次出现的文本。
要是替换命令继续替换之后的文本,则必须使用替换标记(substitution flag),替换标记要放在替换命令字符串之后:
s/pattern/replacement/flags
可用的替换标记有四种:

  • 数字:表示新文本的替换模式
  • g:表示用新文件替换现有文本的全部实例
  • p:表示打印原始行数据
  • w file:将替换的结果写入文件
[root@service99 Sed]# cat replace_test.txt 
2016 2017 2016 end1
asdf 2016 test bind
name 2016 2016 tftp
2016 2016 2016 2016
2017 2017 0000 ssss
[root@service99 Sed]# sed 's/2016/XXXX/2' replace_test.txt  //替换每行第二个2016为XXXX
2016 2017 XXXX end1
asdf 2016 test bind
name 2016 XXXX tftp
2016 XXXX 2016 2016
2017 2017 0000 ssss
[root@service99 Sed]# sed 's/2016/XXXX/' replace_test.txt   //替换每行第一个2016为XXXX
XXXX 2017 2016 end1
asdf XXXX test bind
name XXXX 2016 tftp
XXXX 2016 2016 2016
2017 2017 0000 ssss
[root@service99 Sed]# sed 's/2016/XXXX/1' replace_test.txt  //替换每行第一个2016为XXXX
XXXX 2017 2016 end1
asdf XXXX test bind
name XXXX 2016 tftp
XXXX 2016 2016 2016
2017 2017 0000 ssss
[root@service99 Sed]# sed 's/2016/####/g' replace_test.txt      //替换全部2016为####
#### 2017 #### end1
asdf #### test bind
name #### #### tftp
#### #### #### ####
2017 2017 0000 ssss
[root@service99 Sed]# sed -n 's/2016/2019/p' replace_test.txt  //将替换结果打印输出(没有进行操作的行就不会打印出来,当文件内容较多时都需要添加该标记)
2019 2017 2016 end1
asdf 2019 test bind
name 2019 2016 tftp
2019 2016 2016 2016
//标记的同时使用
[root@service99 Sed]# sed 's/2016/####/2g' replace_test.txt     替换每行第二个(包括第二个)之后所有的2016为####
2016 2017 #### end1
asdf 2016 test bind
name 2016 #### tftp
2016 #### #### ####
2017 2017 0000 ssss
[root@service99 Sed]# sed -n 's/2016/####/2gp' replace_test.txt 
2016 2017 #### end1
name 2016 #### tftp
2016 #### #### ####

替换字符

有时可能会在文本字符串中遇到不容易在替换模式中使用的字符,在Linux中最常见的一个例子是正斜杠。

//将 /bin/bash 替换为 /sbin/nologin
[root@service99 Sed]# cat sed_test.txt | head -5
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
adm:x:3:4:adm:/var/adm:/sbin/nologin
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
[root@service99 Sed]# sed -n 's//bin/bash///sbin/nologin/p' sed_test.txt  
sed: -e expression #1, char 8: unknown option to `s'        //直接修改会报错,由于此时“/”有特殊含义
//需要使用转义字符 “\”  
// 配合 -n ‘p’ 可以更清晰的看见修改效果
[root@service99 Sed]# sed -n 's/\/bin\/bash/\/sbin\/nologin/p' sed_test.txt  
root:x:0:0:root:/root:/sbin/nologin

大家可能觉得这样书写起来十分麻烦,容易混淆和出现错误。
sed允许为替换命令中的字符定界符选择一个不同的字符,这个不同的字符可以是任意字符。

[root@service99 Sed]# sed -n 's#/bin/bash#/sbin/nologin#p' sed_test.txt 
root:x:0:0:root:/root:/sbin/nologin

sed 's9\98\998\97\99' temp_passwd.info //将989替换为8979
sed替换的特殊用法:
sed 's/abc/&d' file //将abc替换为abcd,“/abc/”复制,“&”表示粘贴。该功能可以使用扩展正则的保留“()”“\1”实现

替换命令和正则表达式的配置使用,这里我们以一个实例来进行了解:

在Linux上使用KVM虚拟机时,我们经常有克隆(clone)的需求,在克隆新虚拟机时,需要进行的操作有:

  • 系统镜像文件(img)的增量/快照备份或完全clone
  • 虚拟机配置文件的修改

Linux中需要安装虚拟化组包。
可以使用命令:yum grouplist "Virtual*" 查找
查找结果(英文环境,中文环境下显示的会是汉字)
Virtualization
Virtualization Client
Virtualization Tools
Virtualization Platform
然后使用命令yum groupinstall "组包名“
进行安装。
安装好之后,就可以
ls /etc/libvirt/qemu/
networks rh6_node01.xml rh6_node02.xml rh6_node03.xml rh6_node08.xml rh6_node09.xml rh6_node97.xml rh6_node99.xml

这里我们使用sed来修改虚拟机的配置文件(.xml):

[root@service99 Sed]# cat /etc/libvirt/qemu/rh6_node97.xml
[root@service99 Sed]# cp /etc/libvirt/qemu/rh6_node97.xml kvm_virtual.xml
//需要修改的参数有:name,uuid,source file.mac
[root@service99 Sed]# sed -n '/<name>/p' kvm_virtual.xml 
  <name>rh6_node97</name>
[root@service99 Sed]# sed 's/<name>.*<\/name>/<name>clone_title<\/name>/' kvm_virtual.xml
//两条命令等价
//[root@service99 Sed]# sed 's#<name>.*</name>#<name>clone_title</name>#' kvm_virtual.xml
//还有其他的方法
[root@service99 Sed]# sed -n '/<name>/ s#>.*<#>clone_title<#p' kvm_virtual.xml 
  <name>clone_title</name>
[root@service99 Sed]# sed -i '/<name>/ s#>.*<#>clone_name<#' kvm_virtual.xml
/*前面几条没有添加-i选项的修改,都只是将修改结果输出到了屏幕上,并没有对原文进行修改
 请一定要注意,不要使用-ni命令,这样会让整个文件就剩下你刚才替换的那一行的
 即 不要使用这条命令:sed -ni '/<name>/ s#>.*<#>clone_name<#p' kvm_virtual.xml  
 -n的含义是禁止其他的所有行,-i将结果写入文件 
*/
[root@service99 Sed]# sed -n "/uuid/ s/>.*</>`uuidgen`</p" kvm_virtual.xml 
  <uuid>c93d3b1e-45b3-4565-a297-9a14dc5f3308</uuid>
//[root@service99 Sed]# sed -n "/uuid/ s/>.*</>$(uuidgen)</p" kvm_virtual.xml 
  <uuid>95b8da29-3204-4432-b81e-5fd135c31c9e</uuid>
//注意这个地方要是使用uuidgen这个方法,那么请不要使用单引号,这样会屏蔽函数效果
//所以请使用双引号,sed的语句中,使用单双引号都时可以的,只要注意屏蔽元字符的效果就可以了
[root@service99 Sed]# sed -i "/uuid/ s/>.*</>`$uuidgen`</" kvm_virtual.xml  //文件修改
[root@service99 Sed]# sed -n "/source file/ s#='.*'#='/img/clone_tmp.img'#p" kvm_virtual.xml 
      <source file='/img/clone_tmp.img'/>
[root@service99 Sed]# sed -n "/source file/p" kvm_virtual.xml 
      <source file='/img/clone.img'/>
[root@service99 Sed]# sed -i "/source file/ s#='.*'#='/img/clone_tmp.img'#" kvm_virtual.xml 
[root@service99 Sed]# sed -n "/source file/p" kvm_virtual.xml 
      <source file='/img/clone_tmp.img'/>

/*
现在又会有一个容易出错的地方:
错误命令:sed -i "/source file/ s#='.*'#='/img/clone_tmp.img'#p" kvm_virtual.xml
在后面的那个命令p若是和-i一起执行。就会让原始文件中会将操作的这几行都会再重复出现一边,并在源文件中响应了这些操作。
*/

sed插入和附加文本

  • 插入命令(i)在指定行之前插入一行
  • 附加命令(a)在指定行后面添加新的一行
[root@service99 Sed]#  echo "Line one" | sed 'i FIrsrt'
FIrsrt
Line one
[root@service99 Sed]#  echo "Line one" | sed 'a FIrsrt'
Line one
FIrsrt

当进系sed的一些文件修改的操作时,sed修改的并不是源文件的内容,所以需要添加-i选项,直接修改原文件。
在这李需要注意的是:-i 和 ‘i’ 并不是一回事,前者是sed的一个选项,后者是插入命令。

[root@service99 Sed]# echo "Line one" > line.txt
[root@service99 Sed]# sed 'i "Inster line"' line.txt 
"Inster line"
Line one
[root@service99 Sed]# cat line.txt 
Line one
[root@service99 Sed]# sed  -i 'i Inster line' line.txt 
[root@service99 Sed]# cat line.txt 
Inster line
Line one

如果数据流有多行,而现在需要给最后一行添加数据,则可以:

[root@service99 Sed]# cat line.txt 
Inster line
Line one
[root@service99 Sed]# sed '$a last line' line.txt 
Inster line
Line one
last line

现在进行一个操作,个给文件第一行后面添加多行文本:

[root@service99 Sed]# cat test.info 
DEVICE=eth1
TYPE=Ethernet
ONBOOT=yes
BOOTPROTO=none
IPV6INIT=no
USERCTL=no
IPADDR=192.168.2.99
PREFIX=24
[root@service99 Sed]# sed '1a \
This is add line 1.\
This is add line 2.\
This is add line 3.' test.info 
//输出结果,没有添加-i选项所以并没有对原文修改
DEVICE=eth1
This is add line 1.
This is add line 2.
This is add line 3.
TYPE=Ethernet
ONBOOT=yes
BOOTPROTO=none
IPV6INIT=no
USERCTL=no
IPADDR=192.168.2.99
PREFIX=24
//还可以在第二行之前插入,即使用‘i’

更改行

更改行命令允许更改数据流中整行文本的内容。

[root@service99 Sed]# cat line.txt 
This is line 1.
This is line 2.
This is line 3.
This is line 4.
[root@service99 Sed]# sed '3c This is change line 3.' line.txt 
This is line 1.
This is line 2.
This is change line 3.
This is line 4.

在这里有一个特别的情况,需要说明一下:在更改命令中,可以使用地址范围,但其结果可能不是预期的效果。

[root@service99 Sed]# sed '2,3c \
> This 2,3 change line .' \
> line.txt 
This is line 1.
This 2,3 change line .
This is line 4.
//sed编辑器没有用该文本更改两行,而是使用单一文本行替换了两行   

改变行命令和正则表达式的联合使用

[root@service99 Sed]# cat /etc/sysconfig/network-scripts/ifcfg-eth1
DEVICE=eth1
TYPE=Ethernet
ONBOOT=yes
BOOTPROTO=none
IPV6INIT=no
USERCTL=no
IPADDR=192.168.2.99
PREFIX=24
[root@service99 Sed]# sed '/IPADDR/c IPADDR=192.168.4.99' /etc/sysconfig/network-scripts/ifcfg-eth1 
DEVICE=eth1
TYPE=Ethernet
ONBOOT=yes
BOOTPROTO=none
IPV6INIT=no
USERCTL=no
IPADDR=192.168.4.99
PREFIX=24

变换命令

变换命令(y)是唯一对单个字符进行操作的sed编辑器命令。
命令格式:[address]y/inchars/outchars/

变换命令将inchars和outchars的值进行一对一映射。即inchars的第一个值对应outchars的第一个值,以此类推,若是inchars和outchars的长度不等,则会出现报错。

[root@service99 Sed]# cat line.txt 
This is line 1.
This is line 2.
This is line 3.
This is line 4.
[root@service99 Sed]# sed 'y/123/789/' line.txt 
This is line 7.
This is line 8.
This is line 9.
This is line 4.

替换命令应用示例

  sed -r  's/^.(.*).$/\1/' sed_02_test.info   //删除每一行内的第一个和最后一个字符
  sed -r 's/^..(.*)..$/\1/' sed_02_test.info    //删除每一行内前两个字符和最后两个字符
  sed -r '1s/^..(.*)..$/\1/' sed_02_test.info   //删除第一行的前两个字符和最后两个字符
  sed -r 's/^(.).(.*).(.$)/\1\2\3/' sed_02_test.info    //删除每一行内第二个字符和倒数第二个字符
  sed -r 's/^(.).(.*).(.)$/\1\2\3/' sed_02_test.info    //同上,测试在进行“()”复制操作时,^$是否一定要放置在()内部,测试结果,是没有影响
  sed -r 's/(^.).(.*).(.$)/\1\2\3/' sed_02_test.info
  //sed -r 's/(^.).(.)*.(.$)/\1\2\3/' sed_02_test.info  //错误实现,该表达式只是复制其中一个字符,并不满足需求
  //可以使用s将旧的东西替换为空 s/old

sed的n指令(next)读取下一行

  /*
    sed命令执行时,会先进行读取数据的操作,当读取到数据后,就会按照指令进行对应的操作(比如p打印,d删除),而n指令需要进行的操作是要求sed直接去读取下一行的数据,这样论转下来,就会出现‘n;p’ 可以输出偶数行,‘p:n’可以输出奇数行
    
    即好比一个循环,n指令表示continue命令跳出循环
  */
  sed -n 'n;p' sed_test.info //输出偶数行
  sed -n 'n;d' sed_test.info //删除偶数行
  sed -n 'p;n' sed_test.info //输入奇数行

  sed -n '$=' sed_test.info //显示最后一行的行号
  sed '4,7s/^/#/' a.txt     //4,7行添加注释
  sed 's/^#anon/anon/' vsftpd.conf
  sed 's/^#anon/anon/' /etc/vsftpd/vsftpd.conf

  sed -n '/^DocumentRoot/p' /etc/httpd/conf/httpd.conf
  sed -i '/^DocumentRoot/ s#".*"#"/opt/wwwroot"#' /etc/httpd/conf/httpd.conf
 
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,425评论 4 361
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,058评论 1 291
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,186评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,848评论 0 204
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,249评论 3 286
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,554评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,830评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,536评论 0 197
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,239评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,505评论 2 244
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,004评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,346评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,999评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,060评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,821评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,574评论 2 271
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,480评论 2 267

推荐阅读更多精彩内容

  • linux资料总章2.1 1.0写的不好抱歉 但是2.0已经改了很多 但是错误还是无法避免 以后资料会慢慢更新 大...
    数据革命阅读 12,016评论 2 34
  • 本文承接之前写的三十分钟学会AWK一文,在学习完AWK之后,趁热打铁又学习了一下SED,不得不说这两个工具真的堪称...
    mylxsw阅读 4,361评论 3 74
  • Ubuntu的发音 Ubuntu,源于非洲祖鲁人和科萨人的语言,发作 oo-boon-too 的音。了解发音是有意...
    萤火虫de梦阅读 98,503评论 9 468
  • sed与awk实例 文本间隔 在每一行后面增加一空行 将原来的所有空行删除并在每一行后面增加一空行。这样在输出的文...
    stuha阅读 1,840评论 0 21
  • 本文笔记源自这里——[实验楼]欢迎大家在下面交流其中有问题的地方喜欢请点收藏,每日更新(全部已亲自实践). 一. ...
    东皇Amrzs阅读 3,844评论 7 54