shell

shell.2.4 sed

 

导语

Linux的文本处理三剑客:
grep,egrep,fgrep : 文本过滤器;
sed : Stream EDitor , 流编辑器,对文本内容逐行操作;
awk : 文本格式化工具,报告生成器;

sed工作机制和特性:

1> sed是一个行编辑器,能同时处理多个文件;
2> 默认不直接编辑源文件,而是以行为单位复制到内存执行编译操作;
3> sed读取文件时,一次读取一行内容,把读取的内容放置在sed自己的工作空间进行编辑操作;
4> sed的工作空间叫模式空间(pattern  space);在模式空间对文本进行操作,执行结果输出至标准输出(stdout);
5> sed进行文本过滤时,可以采用正则表达式来匹配模式;被模式匹配到的行经过编辑后输出至标准输出,没有被模式匹配到的行默认直接输出至标准输出,也可以隐藏此标准输出;
6> sed对匹配到的行内容进行编辑操作后,可以保存至另一个内存空间,此空间叫保持空间(hold  space);
7> pattern  space 和 hold  space 的数据可做魔术式的数据交互处理;

图解sed工作机制:

 

1>  逐行读取文件内容,每读取一行内容就放入’pattern  space’中进行模式匹配;
2>  在’pattern  space’中读入的行内容根据模式进行匹配,然后再根据指定的编辑命令做出相关动作:删除、打印、替换等;
3>  未被模式匹配到的行默认动作是输出至标准输出;
4>  文件的每行内容以逐行方式读入’pattern  space’中,文件所有内容只能被读取一次;
5>  ‘hold  space’中默认是没有任何数据的;
6>  ‘pattern  space’与’hold  space’之间可进行数据交互:覆盖、追加;

 

sed命令:
sed – stream  editor  for  filtering  and  transforming  text. 用于过滤和转换文本的流编辑器;

sed命令使用格式:
sed  [OPTION]…  {script-only-if-no-other-script}  [input-file]…

1、 OPTIONS:

-n, –quiet, –silent :  不输出模式空间的内容至屏幕;只显示被模式匹配到的行,未被模式匹配到的行则不显示(‘p’,’d’编辑命令比较特殊,除外);
-e   script, –expression=script : 可以指定多个编辑脚本,实现多点编辑;一个’-e’选项指定一个模式;
-f   script-file, –file=script-file : 指定sed脚本,脚本内容为每行一个编辑命令;

-r, –regexp-extended : 支持扩展正则表达式;

-i[SUFFIX], –in-place[=SUFFIX] : 直接编辑源文件;

NOTE: 多个选项组合使用时候,’-n’,’-r’ 要放置在’-e’前面;

2、 script-only-if-no-other-script : 地址定界编辑命令(由2部分组成);

2.1 地址定界:

1> 空地址: 表示对全文进行编辑处理;
2> 单地址形式:
     # : 表示指定行;
     /pattern/ : 表示被此模式所匹配到的每一行;
3> 地址范围:
    $ : 表示最后一行;
    #,# : 准确数字,从第几行到第几行;
    #,+# : 从第几行开始,后面加多少行;
    #,/pattern/ : 表示从第几行开始,到第一次被模式匹配到的行;
    /pattern1/,/pattern2/ : 表示第一次被模式1匹配到的行,至第一次被模式2匹配到的行;
4> 步进: 用符号表示,~ ;
1~2 : 表示从1开始,步进长度为2,即所有奇数;
2~2 : 表示从2开始,步进长度为2,即所有偶数;

2.2 编辑命令

d : 删除
p : 小写字母’p’,显示模式空间中的内容;

i   \text :   在行前面插入指定的文本内容’text’,支持使用’\n’,可实现多行插入;
a   \text :   在行后面插入指定的文本内容’text’,支持使用’\n’,可实现多行插入;

c   \text :   对匹配到的行(整行内容)替换为指定的文本内容’text’,替换内容后,支持使用’\n’,可实现多行插入;

w   /PATH/TO/SOMEFILE :   保存模式空间中匹配到的行至指定的文件中;
r   /PATH/FROM/SOMEFILE :   读取另一个文件的内容到当前文件被模式匹配到的行后面;可实现文件合并操作;

= :   在被模式匹配到的行的上方(匹配到的行的上面新开一行)打印显示行号;
! :   条件取反,’!’感叹号放在模式与命令之间,中间无空格;是命令取反,而不是模式取反;

s/// :   查找替换操作;其分隔符可自行指定,常用的分隔符有’/’,’@’,’#’等;具体应用有如下;
s///g :  全局替换,默认显示替换后的内容以及未被模式匹配的内容;
s///gw   /PATH/TO/SOMEFILE : 全局查找替换后,替换后的行内容保存至另一个文件,同时默认打印出’替换后的内容以及未被模式匹配的内容’;
s///gp :   全局替换,打印出双份替换后的内容、未被模式匹配到的行内容;

2.3 高级编辑命令

h :  把’pattern  space’中的内容覆盖至’hold  space’;
H :  把’pattern  space’中的内容追加至’hold  space’;

g :  把’hold  space’中的内容覆盖至’pattern  space’;
G :  把’hold  space’中的内容追加至’pattern  space’;

x :  小写字母’x’,把’pattern  space’中的内容与’hold  space’空间中的内容互换;

n :  把匹配到的行的下一行覆盖读入’pattern  space’中;
N :  把匹配到的行的下一行追加读入’pattern  space’中;

d :  删除’pattern  space’中的行;
D :  删除多行’pattern  space’中的所有行;

==================================================================

==================================================================

第一部分:基本编辑命令的使用
==============================

~]# sed '1~2d' /etc/fstab     		删除奇数行,只显示偶数行;

~]# sed -n '1~2d' /etc/fstab     	删除奇数行,不显示偶数行;

~]# sed  '1~2p' /etc/fstab     		匹配奇数行,奇数行会显示;偶数行未被匹配到,但默认也会输出显示;所以:奇数行会显示2遍;

~]# sed  -n '1~2p' /etc/fstab     	匹配奇数行,显示奇数行;'-n' 选项的作用是:不显示未被模式匹配到的行,此处为不显示偶数行;


~]# sed '/^#/d' /etc/fstab          删除'#'号开头的行;


~]# sed '/^[^#]/w /tmp/fstab.new' /etc/fstab  	把非'#'号开头的行复制到另一个文件;
~]# sed '/^#/!w /tmp/fstab.new' /etc/fstab	


从第3行开始,奇数行的上方新开一行打印行号;
---------------------------------------
[root@kouyuushinn ~]# 
[root@kouyuushinn ~]# sed '3~2=' /etc/fstab

#
3
# /etc/fstab
# Created by anaconda on Wed Dec 27 05:42:43 2017
5
#
# Accessible filesystems, by reference, are maintained under '/dev/disk'
7
# See man pages fstab(5), findfs(8), mount(8) and/or blkid(8) for more info
#
9
/dev/mapper/centos-root /                       xfs     defaults        0 0
UUID=78fbb254-bb6a-4847-8890-4410ccb77410 /boot                   xfs     defaults        0 0
11
/dev/mapper/centos-swap swap                    swap    defaults        0 0

13
/dev/sdb1 /sdb1  xfs defaults 0 0 
UUID=6573bffb-af78-4ea2-b4d1-d2303cab8cad /sdb2 ext4 defaults 0 0 
15
UUID=05594ee4-41bd-4c37-b826-650b1f49ad64 /sdb5 xfs defaults 0 0
/dev/sdb6 /sdb6 ext4 defaults 0 0
17
UUID=e8c1aa0f-b241-422c-b05a-a4e34e14672d /mydata ext4 defaults 0 0
UUID=a2180257-513b-4285-92aa-003ed62e2eda /lvdata btrfs defaults 0 0
[root@kouyuushinn ~]# 
[root@kouyuushinn ~]# 



在'UUID'字符串所在行的上方打印行号;
------------------------------------
[root@kouyuushinn ~]# sed '/^UUID/=' /etc/fstab

#
# /etc/fstab
# Created by anaconda on Wed Dec 27 05:42:43 2017
#
# Accessible filesystems, by reference, are maintained under '/dev/disk'
# See man pages fstab(5), findfs(8), mount(8) and/or blkid(8) for more info
#
/dev/mapper/centos-root /                       xfs     defaults        0 0
10
UUID=78fbb254-bb6a-4847-8890-4410ccb77410 /boot                   xfs     defaults        0 0
/dev/mapper/centos-swap swap                    swap    defaults        0 0

/dev/sdb1 /sdb1  xfs defaults 0 0 
14
UUID=6573bffb-af78-4ea2-b4d1-d2303cab8cad /sdb2 ext4 defaults 0 0 
15
UUID=05594ee4-41bd-4c37-b826-650b1f49ad64 /sdb5 xfs defaults 0 0
/dev/sdb6 /sdb6 ext4 defaults 0 0
17
UUID=e8c1aa0f-b241-422c-b05a-a4e34e14672d /mydata ext4 defaults 0 0
18
UUID=a2180257-513b-4285-92aa-003ed62e2eda /lvdata btrfs defaults 0 0
[root@kouyuushinn ~]# 




~]# sed '/^#/d' /etc/fstab      删除'#'开头的行,显示非'#'开头的行;

~]# sed '/^#/!d' /etc/fstab     不删除'#'开头的行,显示'#'开头的行;


删除/etc/fstab文件中所有以空白字符开头的行的行首的所有空白字符;
~]# sed 's/^[[:space:]]\+//gw /tmp/fstab.11' /etc/fstab   
~]# sed 's@^[[:space:]]\+@@gw /tmp/fstab.11' /etc/fstab

删除/etc/fstab文件中所有以#开头的行的行首的#号及#号后面的所有空白字符;
~]# sed  's@^#[[:space:]]*@@gw /tmp/fstab.22' /etc/fstab


删除/etc/fstab文件中所有以#开头的行的行首的#号及#号后面的所有空白字符,以及删除以UUID开头的行;
~]# sed -e 's@^#[[:space:]]\+@@g' -e '/^UUID/d' /etc/fstab

删除/etc/fstab文件中所有以#开头的行的行首的#号及#号后面的所有空白字符,以及删除非UUID开头的行;
~]# sed -e 's@^#[[:space:]]\+@@g' -e '/^[^UUID]/d' /etc/fstab
~]# sed -e 's@^#[[:space:]]\+@@g' -e '/^UUID/!d' /etc/fstab
--------------------------------------------------------------
~]# sed -r -e 's@^#[[:space:]]+@@g' -e '/^UUID/!d' /etc/fstab
~]# sed -r -n -e 's@^#[[:space:]]+@@g' -e '/^UUID/!d' /etc/fstab   选项'-r''-n'在'-e'前面;'-r''-n'顺序可调换;



取出给定路径的'路径名'和'基名':
-------------------------------

[root@kouyuushinn ~]# 
[root@kouyuushinn ~]# dirname /etc/sysconfig/network-scripts/
/etc/sysconfig
[root@kouyuushinn ~]# 
[root@kouyuushinn ~]# dirname /etc/sysconfig/network-scripts/ifcfg-ens33 
/etc/sysconfig/network-scripts
[root@kouyuushinn ~]# 
[root@kouyuushinn ~]# echo "/etc/sysconfig/network-scripts/" | sed 's@[^/]\+/\?$@@' | sed 's@/$@@'
/etc/sysconfig
[root@kouyuushinn ~]# 
[root@kouyuushinn ~]# echo "/etc/sysconfig/network-scripts/ifcfg-ens33" | sed 's@[^/]\+/\?$@@' | sed 's@/$@@'
/etc/sysconfig/network-scripts
[root@kouyuushinn ~]# 
[root@kouyuushinn ~]# 
[root@kouyuushinn ~]# basename /etc/sysconfig/network-scripts/
network-scripts
[root@kouyuushinn ~]# 
[root@kouyuushinn ~]# 
[root@kouyuushinn ~]# basename /etc/sysconfig/network-scripts/ifcfg-ens33 
ifcfg-ens33
[root@kouyuushinn ~]# 
[root@kouyuushinn ~]# 
[root@kouyuushinn ~]# echo /etc/sysconfig/network-scripts/ | egrep -o "[^/]+/?$" | cut -d "/" -f1
network-scripts
[root@kouyuushinn ~]# 
[root@kouyuushinn ~]# echo /etc/sysconfig/network-scripts/ifcfg-ens33 | egrep -o "[^/]+/?$" 
ifcfg-ens33
[root@kouyuushinn ~]# 
[root@kouyuushinn ~]# 



第二部分:高级编辑命令的理解
===============================

[root@kouyuushinn etc]# 
[root@kouyuushinn etc]# cat -n /etc/fstab
     1	
     2	#
     3	# /etc/fstab
     4	# Created by anaconda on Wed Dec 27 05:42:43 2017
     5	#
     6	# Accessible filesystems, by reference, are maintained under '/dev/disk'
     7	# See man pages fstab(5), findfs(8), mount(8) and/or blkid(8) for more info
     8	#
     9	/dev/mapper/centos-root /                       xfs     defaults        0 0
    10	UUID=78fbb254-bb6a-4847-8890-4410ccb77410 /boot                   xfs     defaults        0 0
    11	/dev/mapper/centos-swap swap                    swap    defaults        0 0
    12	
    13	/dev/sdb1 /sdb1  xfs defaults 0 0 
    14	UUID=6573bffb-af78-4ea2-b4d1-d2303cab8cad /sdb2 ext4 defaults 0 0 
    15	UUID=05594ee4-41bd-4c37-b826-650b1f49ad64 /sdb5 xfs defaults 0 0
    16	/dev/sdb6 /sdb6 ext4 defaults 0 0
    17	UUID=e8c1aa0f-b241-422c-b05a-a4e34e14672d /mydata ext4 defaults 0 0
    18	UUID=a2180257-513b-4285-92aa-003ed62e2eda /lvdata btrfs defaults 0 0
[root@kouyuushinn etc]# 
[root@kouyuushinn etc]# sed -n 'n;p' /etc/fstab
#
# Created by anaconda on Wed Dec 27 05:42:43 2017
# Accessible filesystems, by reference, are maintained under '/dev/disk'
#
UUID=78fbb254-bb6a-4847-8890-4410ccb77410 /boot                   xfs     defaults        0 0

UUID=6573bffb-af78-4ea2-b4d1-d2303cab8cad /sdb2 ext4 defaults 0 0 
/dev/sdb6 /sdb6 ext4 defaults 0 0
UUID=a2180257-513b-4285-92aa-003ed62e2eda /lvdata btrfs defaults 0 0
[root@kouyuushinn etc]# 


~]# sed -n 'n;p'  FILENAME       显示偶数行;
分析:
模式没有指定地址空间,所以逐行读取文件;
读取第1行到模式空间,根据'n'编辑命令,读取第2行覆盖至模式空间,第2行被模式匹配,并做打印输出(标准输出);
读取第3行到模式空间,根据'n'编辑命令,读取第4行覆盖至模式空间,第4行被模式匹配,并做打印输出(标准输出);
读取第5行到模式空间,根据'n'编辑命令,读取第6行覆盖至模式空间,第4行被模式匹配,并做打印输出(标准输出);
...

注意: 上面的信息中,虽然读入第4行内容到模式空间后进行了覆盖操作,但之前的被模式匹配到的第2行已经做了打印输出动作,所以不影响最终的显示结果;
       从上面的分析中可看出,被匹配到的都是偶数行,模式匹配后的动作是标准输出;
       选项'-n'的作用是未被模式匹配到的奇数行不做打印输出(静默模式);也就是说,'-n'的作用对象是未被模式匹配到的行;

========================================================
||   重点: !!!  逐行读取,逐行匹配,逐行编辑  !!!  ||
========================================================

~]# sed 'n;d'  FILENAME         显示奇数行;

~]# sed '1!G;h;$!d'  FILENAME   逆序显示文件内容;

~]# sed '$!d'  FILENAME         取出文件最后一行;

~]# sed '$!N;$!D' FILENAME      取出文件最后两行;

~]# sed '/^$/d;G'  FILENAME     删除文件原有的所有空白行,而后为所有的非空白行下面添加一个空白行;

~]# sed 'G' FILENAME            在原有的每行下面添加一个空白行;

 

Leave a Reply

Your email address will not be published. Required fields are marked *