文本处理三剑客之sed
-
sed概述
-
sed使用示例
-
sed的高级应用
sed概述
sed, 作为文本三剑客之一,其定位就是一个编辑器, 而且sed是一个流式编辑器(stream editor),其主要功能是过滤和转换文本。
sed - stream editor for filtering and transforming text
作为一个强大的文本处理功能,sed 自然能够配合正则表达式,另外,所谓流编辑器,sed 是逐行地读取文本,在文本行中应用指定的命令,且默认输出到stdout; sed 拥有两个缓冲区,活跃模式空间(active pattern space)与辅助保持空间(auxiliary hold space), 简称为模式空间与保持空间,且这两个空间默认都为空。
`sed' maintains two data buffers: the active _pattern_ space, and theauxiliary _hold_ space. Both are initially empty.
sed的基本应用只用到模式空间就够了,sed的高级应用需要模式空间与保持空间的想到配合。在sed
的基本应用中,sed会把当前处理的行存储在一个临时缓冲区,即模式空间;然后sed会在模式空间中处理文本,并且传送到标准输出,再接着处理下一行,如
此循环往复,直至文件末尾,这就是sed的基本工作原理。由此可风,sed在默认情况下是不修改原文件的;在sed的高级应用中,多了一个保持空间,保持
空间是与模式空间进行交互的,且以模式空间为主,保持空间为辅,sed匹配的内容最终都得经由模式空间传输至stdout.
常用参数
-
-n: –quiet, –silent, 静默模式,不输出模式空间内容的自动打印
-
-e: –expression=script, 多点编辑,类似于管道
-
-f: –file=script-file, 从指定文件中读取sed脚本
-
-r: 支持使用扩展正则表达式
-
-i: 原处编辑,-i.bak可同时作备份
sed地址定界
所谓sed的地址定界,就是我们对要处理的文本给出一个范围,然后让sed只针对此范围去做相应的处理。
-
不给地址,默认全文处理
-
单地址:
#:指定的行 /pattern/:被此模式所能匹配到的每一行
-
地址范围:
#,#:从多少行到多少行 #,+#:从第#行起至第#行+#行结束(相对地址) #,/part/: 从第#行开始,到第一次匹配到/part/模式结束 /part1/,/part2/: 从第一次匹配到/part1/开始,到最后一次匹配到/part2/结束
-
步进: ~
1~2:奇数行
2~2: 偶数行
sed编辑命令
-
d: 删除模式空间匹配到的行
-
p: 显示模式空间中的内容
-
a \test: 在行后面追加文本,\可用空格替代;支持使用\n 实现多行追加
-
i \test: 在行前面插入文本,\可用空格替代;支持使用\n 实现多行插入
-
c \test: 替换为单选或多行文本,\可用空格替代
-
w /PATH/TO/SOMEFILE: 另存为模式匹配的行到指定文件
-
r /PATH/TO/SOMEFILE: 读取指定文件的文本至模式空间匹配到的行后
-
=: 为模式空间的行打印行号
-
!: 模式空间匹配的行作反处理
-
s///: 查找替换,支持使用其它分隔符,如s@@@, s###
替换标记:
g: 行内全局替换
p: 显示替换成功的行
w /PATH/TO/SOMEFILE:将替换成功的行保存至指定的文件中
sed使用示例
创建一个测试文件:
[root@centos7 ~#]cat f1 1 2 3 4 5
-
删除f1中的空格并写入原文件
[root@centos7 ~#]sed -i '/^$/d' f1
-
删除1-3行
[root@centos7 ~#]sed '1,3d' f1 4 5 [root@centos7 ~#]
-
打印出第2行,并说明默认打印模式空间的意义
[root@centos7 ~#]sed -n '2p' f1 # 只打印出了第2行 2 [root@centos7 ~#][root@centos7 ~#]sed '2p' f1 1 2 # sed 默认显示出模式空间中的2 2 # sed 匹配到第2行并打印出 3 4 5
-
给第2行后加入‘liansir’字样,在第3行前加入‘xiaolei'字样,替换第4行为’lvxing'
[root@centos7 ~#]nl f1 |sed -e '2a \liansir' -e '3i \xiaolei' -e '4c \lvxing' 1 1 # 命令n: nl - number lines of files 2 2 liansir xiaolei 3 3 lvxing 5 5 [root@centos7 ~#]
-
给f1加入空格后并显示空格行号
[root@centos7 ~#]sed -n '/^$/=' f1
-
给数字2后加'liansir'字样,给数字3前加'xiaolei'字样
[root@centos7 ~#]sed -e 's/2/&liansir/' -e 's/3/xiaolei&/' f1
-
删除/etc/grub2.cfg文件中所有以空白开头的行行首的空白字符
[root@centos7 ~#]sed -r 's/^[[:space:]]+//' /etc/grub2.cfg # 以“替换”的方式实现了“删除”,-r 表示使用扩展正则表达式
-
删除/etc/fstab文件中所有以#开头,后面至少跟一个空白字符的行的行首的#和空白字符
[root@centos7 ~#]sed -r 's/^#[[:space:]]*//' /etc/fstab
-
在/root/install.log每一行行首增加#号
[root@centos6 ~#]sed 's/^/#/' /root/install.log 或[root@centos6 ~#]sed -r 's/(.*)/#\1/' /root/install.log # 后向引用,注意使用扩展正则表达式 或[root@centos6 ~#]sed -r 's/(.*)/#&/' /root/install.log
-
处理/etc/fstab路径,使用sed命令取出其目录名和基名 (此题有料,众多解法,有兴趣者探索之)
取基名:下面命令的主要思路是不管前面是什么,只锚定最后一个单词的开头
[root@centos6 ~#]echo '/etc/fstab' |sed -r 's/(.*)\/<//' # 注意转义 /etc/fstab [root@centos6 ~#] [root@centos6 ~#]echo '/etc/fstab' |sed -r 's@(.*)/<@@' # 不想转义可直接换分隔符 /etc/fstab [root@centos6 ~#]echo '/etc/fstab/' |sed -r 's@(.*)/<@@' # 当基名为一个目录时照样适用 /etc/fstab/ [root@centos6 ~#]
取目录名:着眼点还是在后面的基名上,即删除了基名
[root@centos6 ~#]echo '/etc/fstab' |sed -r 's@[^/]+/?$@@' /etc/ [root@centos6 ~#]echo '/etc/' |sed -r 's@[^/]+/?$@@' / [root@centos6 ~#]
取目录名与基名的完美解法
[root@centos6 ~#]echo /etc/fstab |sed -r 's@(.*/)([^/]+/?)$@\1@' # 取目录名 /etc/ [root@centos6 ~#]echo /etc/fstab |sed -r 's@(.*/)([^/]+/?)$@\2@' # 取基名 fstab [root@centos6 ~#]
完美之外:
1. 涉及到/ 时则换分隔符,避免转义,如@ 2. 将目录名与基名以分组的形式分别表示出来,表达了一个完整的路径 3. 分别后向引用则可取得目录名或基名,属于通用解法
-
利用sed 取出ifconfig命令中本机的IPv4地址 # 先打印出本机IP所在行,然后"掐头去尾"。
[root@centos7 ~#]ifconfig |sed -n '2p' |sed -e 's/.*inet//' -e 's/net.*//' 10.1.253.100 [root@centos7 ~#]
-
统计centos安装光盘中Package目录下的所有rpm文件的以.分隔倒数第二个字段的重复次数
[root@centos6 /media/CentOS_6.8_Final/Packages#]ls |sed -r 's@.*\.(.*)\.rpm$@\1@' |sort |uniq -c 4 i686 919 noarch 1 TRANS.TBL 2283 x86_64 [root@centos6 /media/CentOS_6.8_Final/Packages#] # 注意\.是转义.
至此,我们再来了解下sed的高级应用!
sed高级编辑命令:
-
h: 把模式空间中的内容覆盖至保持空间中
-
H: 把模式空间中的内容追加至保持空间中
-
g: 从保持空间读取数据覆盖至模式空间中
-
G: 从保持空间读取数据追加至模式空间中
-
x: 把模式空间中的内容与保持空间的内容进行互换
-
n: 读取匹配到的行的下一行覆盖至模式空间
-
N: 读取匹配到的行的下一行追加至模式空间
-
d: 删除模式空间中的行
-
D: 删除当前模式空间开端至\n的内容(不再传至标准输出),放弃之后的命令,但是对剩余模式空间重新执行sed.
h H Copy/append pattern space to hold space. g G Copy/append hold space to pattern space. x Exchange the contents of the hold and pattern spaces. n N Read/append the next line of input into the pattern space. d Delete pattern space. Start next cycle.
可见,模式空间与保持空间的交互命令有:h, H, g, G, x.其流向关系可用下图表示:
sed高级应用示例
创建一个测试文件:
[root@centos7 ~#]echo {1..5} |tr ' ' '\n' >f1 [root@centos7 ~#]cat f1 1 2 3 4 5 [root@centos7 ~#]
-
输出偶数行与奇数行:
普通用法: [root@centos7 ~#]sed -n '1~2p' f1 1 3 5 [root@centos7 ~#]sed -n '2~2p' f1 2 4 [root@centos7 ~#] 高级用法: [root@centos7 ~#]sed 'n;d' f1 1 3 5 [root@centos7 ~#]sed -n 'n;p' f1 2 4 [root@centos7 ~#]
高级用法解析:
~#]sed 'n;d' f1 首先,sed读入第一行的1到模式空间,n动作匹配到第二行中的2并覆盖掉 模式空间中的1,此时模式空间中仅有2,又因为d动作被删除了,模式空间全 空了!那怎么又输出1了呢?这是因为sed 没有使用-n选项,故1在被2覆盖之 前已被sed默认输出,而2在模式空间却被d给干掉了,故而屏幕上输出了1。 然后sed双读入第三行中的3,被n匹配至其下一行中的4并读入模式空间,但 在4覆盖3之前sed已默认打印出3,而4却“胎死腹中”,故屏幕双留下了3. ~#]sed -n 'n;p' f1 首先,sed 读入第一行的1到模式空间,因为n动作,又匹配到第二行中的2, 并把2读入模式空间覆盖掉之前的1,模式空间中的内容输入至stdout而得到2. 然后,sed读入第三行中的3到模式空间,因为n动作,匹配到其下一行中的4, 并把4读入模式空间并覆盖掉之前的3并p至stdout.
-
倒序输出:
[root@centos7 ~#]sed '1!G;h;$!d' f1 5 4 3 2 1 [root@centos7 ~#]
高级用法解析
~#]sed '1!G;h;$!d' f1 这个sed命令,整体被分别;分隔为三段,我们认为他有三个动作: 1!G; 如果不是第1行,则把保持空间中的内容追加至模式空间(保持空间默认为空) h; 把模式空间中的内容覆盖至保持空间 $!d 如果不是最后一行则删除 结合sed流编辑器的特点,逐行读入,意味每读入一行便会执行上面的三个动作; 每一行: 1. sed读入第一行中的1到模式空间,由于不符合'1!'这个条件,则跳过G执行h; 2. h 把模式空间中的1覆盖至保持空间;(此时模式空间中为1,保持空间中为1) 3. 1不是最后一行,符合条件'$!',删除(此时模式空间为空,保持空间都为1) 第二行: 1. sed读入第二中的2至模式空间,符合'1!'这个条件,从而执行G动作,G把 保持空间中的1追加至模式空间; 于是,此时模式空间中的内容为: 2 1 但保持空间是1 2. h 把模式空间中的内容覆盖至保持空间 3. 执行 $!d(模式空间为空) 依次类推,当执行完第四步时,情况是这样的:模式空间为空,保持空间的内容为: 4 3 2 1 第五步: 1. sed读入第五行中的内容5至模式空间,符合'1!'这个条件,执行G动作,把 保持空间中的内容追加到模式空间 2. h 把模式空间中的内容覆盖至保持空间 3. 第五行是最后一行,不符合'$!',跳过$!d于是,屏幕上显示: 5 4 3 2 1
一个sed的高级命令,应得大费如此篇幅,目的就是更为深入地理解sed这个流编辑器,逐行处理文本,有两个模式空间,一主一辅。看下图(图片来自网友),就更能清楚地理解sed的工作原理了。
此图仅供参考!
-
一锅上了先
[root@centos7 ~#]sed '$!N;$!D' f1 4 5 [root@centos7 ~#] [root@centos7 ~#]sed '$!d' f1 # 不是最后一行则删除,意味着最后一行保留输出 5 [root@centos7 ~#] [root@centos7 ~#]sed 'G' f1 # 保留空间默认为空 1 2 3 4 5 [root@centos7 ~#] [root@centos7 ~#]sed 'g' f1 [root@centos7 ~#]sed 'g' f1 |wc -l # 可见输出了5个空格 5 [root@centos7 ~#] [root@centos7 ~#]sed '/^$/d;G' f1 1 2 3 4 5 [root@centos7 ~#] [root@centos7 ~#]sed -n '1!G;h;$p' f1 # 看与高级应用分析与区别 5 4 3 2 1 [root@centos7 ~#]
4. 交换模式空间与保持空间的内容 [root@centos7 ~#]sed 'x' f1 # 模式空间中最后交换了一行被保留空间中第一个空白替换了 1 2 3 4 [root@centos7 ~#]
sed 的功能如此强大,掌握也非一日之功,sed可以帮助我们自动编辑一个或多个文件,简化对文件的反复操作,编写程序转换等。
原创文章,作者:Liansir,如若转载,请注明出处:http://www.178linux.com/33184