您的位置:首页 > 其它

文本处理三剑客之sed

2016-08-10 21:23 225 查看

文本处理三剑客之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可以帮助我们自动编辑一个或多个文件,简化对文件的反复操作,编写程序转换等。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  过滤 sed 文本处理