sed文本处理工具

时间:2022-11-18 12:36:21

Sed 简介

sed是一种新型的,非交互式的编辑器。它能执行与编辑器vi ex相同的编辑任务。sed编辑器没有提供交互式使用方式,使用者只能在命令行输入编辑命令、指定文件名,然后在屏幕上查看输出。sed 编辑器没有破坏性,它不会修改文件,除非使用 shell重定向来保存输出结果。默认情况下,所有的输出行都被打印到屏幕上。

sed工作过程

sed编辑器逐行处理文件(或输入),并将输出结果发送到屏幕。sed的命令就是在 vied/ex 编辑器中见到的那些。 sed 把当前正在处理的行保存在一个临时缓存区中,这个缓存区称为模式空间或临时缓冲。sed处理完模式空间中的行后(即在该行上执行sed 命令后),就把改行发送到屏幕上(除非之前有命令删除这一行或取消打印操作)。sed 每处理完输入文件的最后一行后, sed 便结束运行。 sed 把每一行都存在临时缓存区中,对这个副本进行编辑,所以不会修改或破坏源文件。如图 1sed 处理过程。
sed文本处理工具

从上图可以看出sed不是破坏性的,它不会修改正在编辑的文件。

 

Sed 命令格式

1
sed 命令行格式为: sed [选项] ‘ command ’ 输入文本

Sed定位

Sed命令在没有给定的位置时,默认会处理所有行;
Sed 支持一下几种地址类型:
1first~step
这两个单词的意思: first 指起始匹配行, step 指步长,例如: sed -n 2~5p 含义:从第二行开始匹配,隔 5 行匹配一次,即 2,7,12.......
2$
这个$符表示匹配最后一行。
3/REGEXP/
这个是表示匹配正则那一行,通过//之间的正则来匹配。
4\cREGEXPc
这个是表示匹配正则那一行,通过\c c 之间的正则来匹配,c可以是任一字符
5addr1add2
定址addr1add2 决定用于对哪些行进行编辑。地址的形式可以是数字、正则表达式或二者的结合。如果没有指定地址,sed 将处理输入文件中的所有行。如果定址是一个数字,则这个数字代表行号,如果是逗号分隔的两个行号,那么需要处理的定址就是两行之间的范围(包括两行在内)。范围可以是数字,正则或二者组合。

6addr1+N

addr1这行到往下 N 行匹配,总共匹配 N+1
7addr1~N
Will match addr1 and the lines following addr1 until the next line whose input line number is a multiple of N.【没有看懂是什么意思】

Sed的正则表达式

1sed的正则表达式元字符

元字符 功 能 示 例 示例的匹配对象
^ 行首定位符 /^love/ 匹配所有以 love 开头的行
$ 行尾定位符 /love$/ 匹配所有以 love 结尾的行
. 匹配除换行外的单
个字符
/l..e/ 匹配包含字符 l、后跟两个任意
字符、再跟字母 e 的行
* 匹配零个或多个前
导字符
/*love/ 匹配在零个或多个空格紧跟着
模式 love 的行
[] 匹配指定字符组内
任一字符
/[Ll]ove/ 匹配包含 love Love 的行
[^] 匹配不在指定字符
组内任一字符
/[^A-KM-Z]ove/ 匹配包含 ove,但ove之前的那
个字符不在 A K M Z
的行
\(..\) 保存已匹配的字符
& 保存查找串以便在
替换串中引用
s/love/**&**/ 符号&代表查找串。字符串love
将替换前后各加了两个**的引
用,即 love 变成**love**
\< 词首定位符 /\<love/ 匹配包含以 love 开头的单词的
\> 词尾定位符 /love\>/ 匹配包含以 love 结尾的单词的
x\{m\} 连续 m x /o\{5\}/ 分别匹配出现连续 5 个字母 o
至少 5 个连续的 o、或 5~10
连续的 o 的行
x\{m,\} 至少 m x /o\{5,\}/
x\{m,n\} 至少 m x,但不
超过 n x
/o\{5,10\}/

sed的常用选项

2.sed的常用选项

选项 说明
-n 使用安静模式,在一般情况所有的 STDIN 都会输出到屏幕上,加入-n 后只打印
sed 特殊处理的行
-e 多重编辑,且命令顺序会影响结果
-f 指定一个 sed 脚本文件到命令行执行,
-r Sed 使用扩展正则
-i 直接修改文档读取的内容,不在屏幕上输出

Sed 操作命令

sed 操作命令告诉 sed 如何处理由地址指定的各输入行。如果没有指定地址, sed 就会处理输入的所有的行。表 3.sed 命令

命 令 说 明
a\ 在当前行后添加一行或多行
c\ 用新文本修改(替换)当前行中的文本
d 删除行
i\ 在当前行之前插入文本
h 把模式空间里的内容复制到暂存缓存区
H 把模式空间里的内容追加到暂存缓存区
g 取出暂存缓冲区里的内容,将其复制到模式空间,覆盖该处原有内容
G 取出暂存缓冲区里的内容,将其复制到模式空间,追加在原有内容后面
l 列出非打印字符
p 打印行
n 读入下一输入行,并从下一条命令而不是第一条命令开始处理
q 结束或退出 sed
r 从文件中读取输入行
对所选行意外的所有行应用命令
s 用一个字符串替换另一个


表 4.替换标志

g 在行内进行全局替换
p 打印行
w 将行写入文件
x 交换暂存缓冲区与模式空间的内容
y 将字符转换为另一字符(不能对正则表达式使用 y 命令)


报错信息和退出信息

遇到语法错误时, sed 会向标准错误输出发送一条相当简单的报错信息。但是,如果 sed判断不出错在何处,它会“断章取义”,给出令人迷惑的报错信息。如果没有语法错误, sed将会返回给 shell 一个退出状态,状态为 0 代表成功,为非 0 整数代表失败。


案例:  

    sed -n '1p' passwd 只打印第一行
    ifconfig eth1 |sed -n 2p
    seq 100 |sed -n '1~2p'步进,只显示奇数行
    seq 100 |sed -n '2~2p'步进,只显示偶数行
    sed -i.orig 's/dog/cat/g' pets 备份后再替换
    sed '2a\dog cat dog cat cat' pets 在第二行后增加新行
    sed '2i\dog cat dog cat cat' pets 在第二行前增加新行
    sed '2c\dog cat dog cat cat' pets 替换第二行
    sed '2w /path/filename' pets 将第二行保存到指定文件
    sed '2r /path/filename' pets 将指定文件读取并加到第二行后
    sed '=' pets 在显示的结果前显示行号

sed -n 'n;p' FILE
    显示偶数行
sed '1!G;h;$!d' FILE
    逆向显示文件内容
sed 'N;D'  FILE
    仅显示最后一行
sed '$!N;$!D' FILE
    仅显示文件最后两行
sed '$!d' FILE
    仅保留最后一行
sed ‘G’ FILE
    每行后加一个空行
sed ‘g’ FILE
    将每行内容替换为空行
sed ‘/^$/d;G’ FILE
    每行后加一个空行,已有空白行的,仅显示一个空白行
sed 'n;d' FILE
    显示奇数行
sed -n '1!G;h;$p' FILE
    逆向显示文件内容

习题:

1、删除/etc/grub2.conf文件中所有以空白开头的行行首的空白字符

[root@centos7 ~]# sed -r 's@^[[:space:]]\+@@' /etc/grub2.cfg

2、删除/etc/fstab文件中所有以#开头,后面至少跟一个空白字符的行的行首的#和空白字符

[root@centos7 ~]# sed -r 's@^#[[:space:]]+@@' /etc/fstab

3、在/etc/fstab每一行行首增加#号

[plain] view plain copy
  1. [root@centos7 ~]# sed -e 's@^@#&@' -e 's@^$@#@' /etc/fstab  

或者

[root@centos7 ~]# sed 's@^.*@#&@' /etc/fstab

注意:此处不可写成sed 's@^(.*)@#$@' /etc/fstab,这是错误的,此处锚定的是(),而不是行首

      空白行锚定使用^$

[root@centos7 ~]# cat > f1
()
a
b
^C
[root@centos7 ~]# sed 's@^(.*)@#&@' f1
#()   
a
b

4、在/etc/fstab文件中不以#开头的行的行首增加#号

[root@centos7 ~]# sed 's@^[^#]@#&@' /etc/fstab

5、处理/etc/fstab路径,使用sed命令取出其目录名和基名

[root@centos7 ~]# echo /etc/fstab | sed -r 's@(.*/)([^/]+/?$)@\1@'
/etc/
[root@centos7 ~]# echo /etc/fstab | sed -r 's@(.*/)([^/]+/?$)@\2@'
fstab

6、利用sed 取出ifconfig命令中本机的IPv4地址

[root@centos7 ~]# ifconfig | sed -n '2p' | sed -e 's@.*inet[[:space:]]@@' -e 's@[[:space:]].*@@'

或者

[root@centos7 ~]# ifconfig | sed -n '2p' | sed -r 's@.*inet[[:space:]](.*)[[:space:]]net.*@\1@'
10.1.0.17

当然,如果使用cut就简单多了

[root@centos7 ~]# ifconfig | sed -n '2p' | tr -s ' ' | cut -d' ' -f3
10.1.0.17

7、统计centos安装光盘中Package目录下的所有rpm文件的以.分隔倒数第二个字段的重复次数

[root@centos7 Packages]# ls | grep "rpm$" | sed -e 's@.rpm$@@' -e 's@.*\.@@' | sort | uniq -c
   2000 i686
   2938 noarch
   4069 x86_64

或者

[root@centos7 Packages]# ls | grep "rpm$" | sed -r 's@.*\.(.*)\.rpm@\1@' | sort | uniq -c
   2000 i686
   2938 noarch
   4069 x86_64

8、统计/etc/init.d/function中每个单词的重复次数,并倒序排列

  1. [root@centos7/etc/yum.repos.d]#cat /etc/init.d/functions | tr -c '[:alpha:]' '\n' | tr -s '\n' | sort | uniq -c | sort -nr  

注意常见的错误

使用正则表达式注意.的转义

使用扩展正则表达式注意分组时要加-r

再或者

[root@centos7 Packages]# ls | grep "rpm$" | rev | cut -d. -f2 | sort | uniq -c
   4069 46_68x
   2000 686i
   2938 hcraon
总结:个人认为,sed命令是grep命令的延伸,虽然有些功能比如筛选同样的行时,俩者都可实现,但是如果数据量很大的话,相比而言,grep是更加方便的。所以grep筛选数据,sed再处理数据,这样无疑是最好的结果。至于截取特定的字段的话,cut、tr、grep和sed同样都可以实现,而sed又无疑是这三个里面最强大的(分组截取字段),所以这些要勤加练习,才能掌握的游刃有余。