sed命令使用技巧

sed全称 Stream EDitor, 行编辑器 ,是一种流编辑器,它一次处理一行内容。处理时,把当前处理的行存储在临时缓冲区中,称为“模式空间”(pattern space),接着用sed命令处理缓冲区中的 内容,处理完成后,把缓冲区的内容送往屏幕。然后读入下行,执行下一个循环。 如果没有使诸如‘D’的特殊命令,那会在两个循环之间清空模式空间,但不会清 空保留空间。这样不断重复,直到文件末尾。文件内容并没有改变,除非你使用重 定向存储输出。
sed主要用来自动编辑一个或多个文件,简化对文件的反复操作,编写转换程序等

使用格式:sed [OPTION]... {script} [input-file]...

选项说明:
-n 不输出模式空间的内容到屏幕
-r 支持使用扩展正则表达式
-e 多点编辑,即能够多次对模式空间内容进行编辑
-f /Path/script_file 从指定路径读取编辑脚本
-i.bak 单纯-i是直接修改文件,加上.bak或者任意.xxx 表示先备份源文件再修改

script说明:
用来做地址界定用,以下几种地址界定形式:
1 不写地址界定表示全文检索;
2 #,# 其中#代表行号,表示从第几行到第几行;#,+#表示从某一行往后检索+#行;
3 /part/ 能够被正则表达part匹配的所有行;也可以和行号配合使用#,/part/表示从某一行开始匹直到匹配到part模式。注意没有/part/,#这种界定格式
4 $表示最后一行,和上面的界定符配合使用#,$ 表示第#行到最后一行;
5 ~表示步进,例如1~2奇数行,2~2偶数行,3~5从第三行开始每5行取行

编辑命令:
在地址界定完成后就需要指定对界定到的行如何处理,具体处理指令如下
d: 删除模式空间匹配的行,并立即启用下一轮循环
p:打印当前模式空间内容,追加到默认输出之后
a []text:在指定行后面追加文本 支持使用\n实现多行追加
i []text:在行前面插入文本
c []text:替换行为单行或多行文本
w /path/somefile: 保存模式匹配的行至指定文件
r /path/somefile:读取指定文件的文本至模式空间中 匹配到的行后
=: 在界定到的每一行的前面插入该行行号
!:模式空间中匹配行取反处理
n 读取下一个输入行,用下一个命令处理新的行而不是用第一个命令

以上选项即命令可以组成如下格式,
sed -选项 '地址界定编辑命令 ' 被编辑文本
地址界定符完成后紧跟编辑命令
例如:
sed -n '10,$aHello Sed' /etc/passwd
表示取/etc/passwd 第10行到最后一行通过编辑命令a在取到的每一行后面添加一行内容Hello Sed,但匹配的到行即模式空间内容不输出到屏幕,因此只会输出10到最后一行每一行后面添加的Hello Sed行,以下是结果:

[root@centos7 16:14:30 ~]#sed  -n '45,$aHell Sed' /etc/passwd
Hell Sed
Hell Sed
Hell Sed
Hell Sed
Hell Sed

如果不使用-n选项则会是以下效果:

[root@centos7 16:15:57 ~]#sed   '45,$aHell Sed' /etc/passwd | tail -12
mongodb:x:1003:1005::/home/mongodb:/bin/bash
base:x:1004:1006::/home/base:/bin/bash
bash:x:1005:1007::/home/bash:/bin/bash
Hell Sed
testbash:x:1006:1008::/home/testbash:/bin/bash
Hell Sed
nologin:x:1008:1010::/home/nologin:/sbin/nologin
Hell Sed
sh:x:1009:1011::/home/sh:/bin/bash
Hell Sed
apache:x:48:48:Apache:/usr/share/httpd:/sbin/nologin
Hell Sed
[root@centos7 16:16:02 ~]#

假设这里满足了对文件修改的需求,就可以将参数选项缓存-i让修改内容在文件中立即生效

再例如,需要删除某些行,则可以这么处理:

[root@centos7 16:25:00 ~]#sed  '1,+40d'  /etc/passwd
docker:x:1002:1004::/home/docker:/bin/bash
mongodb:x:1003:1005::/home/mongodb:/bin/bash
base:x:1004:1006::/home/base:/bin/bash
bash:x:1005:1007::/home/bash:/bin/bash
testbash:x:1006:1008::/home/testbash:/bin/bash
nologin:x:1008:1010::/home/nologin:/sbin/nologin
sh:x:1009:1011::/home/sh:/bin/bash
apache:x:48:48:Apache:/usr/share/httpd:/sbin/nologin
[root@centos7 16:25:19 ~]#
表示删除从1第行到第41行如果这里加上-i 选项则对/etc/passwd生效

以上是地址界定配合编辑命令的使用,下面介绍查找替换命令s///的使用:
s/// 或者将/符号换成其它分隔符都可以例如,s@@@ s###
在查找替换命令s///后可以跟一些替换标记来,例如
s///g 表示行内全局替换,即每一行所有符合模式的字符都会被替换
s///p 查找替换后并打印
w /PATH/TO/SOMEFILE:将替换成功的行保存至文件中

下面列举以下典型的例子帮助个人理解(centos6系统):

1、复制/etc/rc.d/rc.sysinit文件至/tmp目录,将/tmp/rc.sysinit文件中的以至少一个空白字符开头的行的行首加#。

[root@centos6 15:08:14 ~]#cp /etc/rc.d/rc.sysinit /tmp
[root@centos6 15:16:08 ~]#sed -n '13,13p' /etc/rc.sysinit 
    . /etc/sysconfig/network
[root@centos6 15:16:25 ~]#sed  's/\(^[[:space:]]\)/#\1/g' /tmp/rc.sysinit | sed -n '13,13p'
#    . /etc/sysconfig/network
[root@centos6 15:17:05 ~]#
这里只是为了方便展示出结果因此只打印出更改后生效的第13行

2 将/etc/yum.repos.d/repobak/CentOS-Media.repo文件中所有的enabled=0或gpgcheck=0的最后的0修改为1

[root@centos6 15:23:31 ~]#cat !$
cat /etc/yum.repos.d/repobak/CentOS-Media.repo
# CentOS-Media.repo
#
#  This repo can be used with mounted DVD media, verify the mount point for
#  CentOS-6.  You can use this repo and yum to install items directly off the
#  DVD ISO that we release.
#
# To use this repo, put in your DVD and use it with the other repos too:
#  yum --enablerepo=c6-media [command]
#  
# or for ONLY the media repo, do this:
#
#  yum --disablerepo=\* --enablerepo=c6-media [command]

[c6-media]
name=CentOS-$releasever - Media
baseurl=file:///media/CentOS/
        file:///media/cdrom/
        file:///media/cdrecorder/
gpgcheck=0
enabled=0
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-6
[root@centos6 15:23:41 ~]#
可以看到两个参数的值都是0,使用sed修改:
[root@centos6 15:23:41 ~]#sed   -e 's/enabled=0/enabled=1/' -e 's/gpgcheck=0/gpgcheck=1/'  /etc/yum.repos.d/repobak/CentOS-Media.repo | tail -3
gpgcheck=1
enabled=1
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-6
也可以写成:
[root@centos6 15:25:17 ~]#sed 's/enabled=0/enabled=1/;s/gpgcheck=0/gpgcheck=1/'  /etc/yum.repos.d/repobak/CentOS-Media.repo | tail -3
gpgcheck=1
enabled=1
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-6

3 打印奇数行和偶数行
偶数行:

[root@centos6 15:33:17 ~]#sed -n 'n;p' /etc/passwd
[root@centos6 15:35:00 ~]#sed -n '2~2p' /etc/passwd
奇数行:
[root@centos6 15:35:55 ~]#sed -n '1~2p' /etc/passwd
[root@centos6 15:36:00 ~]#sed -n 'p;n' /etc/passwd

4 n命令的作用

[root@centos7 17:18:18 ~]#cat passwd.out 
docker:x:1002:1004::/home/docker:/bin/bash
mongodb:x:1003:1005::/home/mongodb:/bin/bash
base:x:1004:1006::/home/base:/bin/bash
bash:x:1005:1007::/home/bash:/bin/bash
testbash:x:1006:1008::/home/testbash:/bin/bash
nologin:x:1008:1010::/home/nologin:/sbin/nologin
sh:x:1009:1011::/home/sh:/bin/bash
apache:x:48:48:Apache:/usr/share/httpd:/sbin/nologin
[root@centos7 17:18:27 ~]#sed  '/docker/n;s/mongodb/manguo/g;' passwd.out 
docker:x:1002:1004::/home/docker:/bin/bash
manguo:x:1003:1005::/home/manguo:/bin/bash
base:x:1004:1006::/home/base:/bin/bash
bash:x:1005:1007::/home/bash:/bin/bash
testbash:x:1006:1008::/home/testbash:/bin/bash
nologin:x:1008:1010::/home/nologin:/sbin/nologin
sh:x:1009:1011::/home/sh:/bin/bash
apache:x:48:48:Apache:/usr/share/httpd:/sbin/nologin
[root@centos7 17:18:29 ~]#
这里先使用匹配模式匹配到docker行,即第一行,n命令表示继续读取docker行的后一行并将读取到的行交给s查找替换来处理,查找替换将mongodb替换成manguo

另外需要注意的sed匹配的贪婪模式,如下图
sed命令使用技巧
图中第一个命令还不太能说明问题,在第二个匹配结果有两组,sed先匹配到root开头的第一行保存后,再去匹配bin,此时从第二行读入发现恰好也匹配到了bin,因此本次/root/,/bin/模式匹配完成。但是sed不会停止反而会继续往下匹配。因此接下来发现第三行(operator开头行)中包含root 然后保存,再继续往下一行去匹配bin,找到后保存。
这时候就有了第二组/root/,/bin/模式。sed会继续再往下搜索但是没有再匹配到/root/,/bin/模式而结束。打印输出匹配到的两组结果!

猜你喜欢

转载自blog.51cto.com/4081735/2106518