通过vim,grep及正则的蹂躏以后,就可以看看另一把利器sed
简介
sed全称Stream Editor,顾名思义为流编辑器,也习惯叫行编辑器,处理文本的方式为按行至上而下读取,匹配,处理并显示或者做其它处理,区别与vim那种全屏编辑器,直接上个工作原理图
命令运行会在内存开辟模式空间和保持空间2个空间用来处理文本内容
- 读取文本第一行内容至模式空间
- 当内容没有匹配时,默认会输出,当有匹配时则进行编辑操作(修改,替换,删除,追加,显示等)
- 处理第一行后,将内容输出,再对第二行处理直到文本结束
模式空间和保存空间
默认情况下,sed是将输入内容一行一行进行处理的,如:sed ‘1,$p’ /etc/passwd
。处理过程中,sed会一行一行的读入/etc/passwd文件,查看每行是否匹配定址条件(1,$),如果匹配条件,就讲行内容放入模式空间,并打印(p命令)。由于文本流本身的输出,而模式空间内容又被打印一遍,所以这个命令最后会将每一行都显示2遍,默认情况下,sed程序在所有的脚本指令执行完毕后,将自动打印模式空间中的内容,这会导致p命令输出相关行两遍,-n
选项可以屏蔽自动打印
模式空间(pattern space)
用于缓存要处理的内容,是sed处理最核心的缓存空间,所有要处理的行内容都会复制进这个空间再进行修改,或根据需要显示。默认sed不会修改原文件本身内容,只修改模式空间内容
保存空间(hold space)
除了模式空间以外,sed还实现了另一个内容缓存空间,叫保存空间。可以理解这个空间跟模式空间一样,也就是一段内存空间,一般情况下不用,除非我们使用相关指令才会对它进行使用
语法
sed [OPTION] 'script' FILE...
script中有变量引用时用双引号
常用的选项
-n
: 不输出模式空间中的内容-r
: 使用扩展正则表达式-e
: 可以使用多个命令脚本进行操作-f sed_script
: 从指定的文本中读取处理脚本-i
: 直接编辑原文件,默认不对原文件进行操作
script
script由地址定界
和编辑命令
组成,二者间不能有空格,如:’2,5d’
地址定界
界定处理的范围
空地址
:全文m
:指定第m行$
:最后一行/pattern/
:被此模式匹配到的每一行m,n
:从第m行到n行m,+n
:从第m行到m+n行m,/pattern/
:从第m行到第一次模式匹配到的行/pat1/,/pat2/
:第一次被模式1匹配的行到第一次被模式2匹配到的行1~2
:奇数行2~2
:偶数行
编辑命令
对地址定界下匹配到的内容执行的操作
d
:删除匹配到的行p
:打印模式空间中的内容注意:默认情况下是把“模式空间”中的内容全部进行显示,所以其显示的结果是“默认的显示内容+p的内容”,即匹配的行显示2次,通常与-n选项一起使用,表示只显示匹配到的行
a \text
:append,在匹配到的行之后追加text,支持\n实现多行插入i \text
:insert,在匹配到的行之前追加textc \text
:change,把匹配到的行和给定的文本进行交换w file
:将匹配到的内容另存到指定的文件中r file
:将读取指定的文件内容到匹配的行处(如果指定文件为多行时,追加到匹配行之后)=
:为匹配到的行在上一行添加行号 ,如sed ‘=’ /etc/fstab!
:条件取反,格式为地址定界!编辑命令,如’5!d’表第5行不删s/pattern/str/[修饰符]
:查找替换,常用s@@@和s###修饰符:g全局,默认只匹配每一行的第一个; i不区分大小写; p显示替换成功的行
后向引用:\(**\)
,\1,\2...
对应括号内容,&表示引用匹配到整个y/inchars/outchars/
:全局转换命令,会进行inchars和outchars的一对一转换
1 | # 打印第二行到第一次以#开头的行 |
高级命令
所谓的高级就是用上图示中的保持空间的功能,可以实现模式空间与保持空间中的内容互相替换,追加,删除等操作,以得到各种匪夷所思的结果,做了解即可
h:模式空间–>覆盖–>保持空间
H:模式空间–>追加–>保持空间(加在原有内容之后)
g:保持空间–>覆盖–>模式空间
G:保持空间–>追加–>模式空间(加在原有内容之后)
x:模式空间<–交换–>保持空间
d:删除模式空间中的内容
D:如果模式空间中的内容为多行时,删除模式空间中的第一行
n:读取匹配到的行的下一行到模式空间中(覆盖原内容)
N:读取匹配到的行的下一行到模式空间中(追加在原内容之后)
*注:多处命令间用分号隔开,实现多点编辑,追加或覆盖操作时原空间内容依然存在
1 | sed -n 'n;p' file # 显示偶数行 |
示例说明
转载自:http://liwei.life/2016/07/04/sed/
ifconfig
信息保存至ifconfig.out
1 | sed -n '/^[^ ]/{s/^\([^ ]*\) .*/\1/g;h;: top;n;/^$/b;s/^.*RX bytes:\([0-9]\{1,\}\).*/\1/g;T top;H;x;s/\n/:/g;p}' ifconfig.out |
为方便分析,将其写成sed脚本
1 | [zorro@zorrozou-pc0 ~]$ cat -n ifconfig.sed |
第3,4行:找到网卡名的行并且在模式空间里只保留网卡名称
第5行:h命令的意思是,将现在模式空间中的内容,放到保存空间。于是,网卡名就放进了保存空间
第6行:top在这里只起到一个标记的作用。我们使用:标记了一个位置名叫top。我们先暂时记住它
第7行:n命令。这个命令就是读取下一行到模式空间。就是说,网卡行已经处理完,并且保存好了,可以n读入下一行了。n之后,下一行的内容就进入模式空间,然后继续从n下面的命令开始处理
第8行:使用的是b命令,用来跳出本次sed处理。这里的含义是检查下一行内容如果是空行/^$/,就跳出本段的sed处理,说明这段网卡信息分析完毕,可以进行下一段分析了。如果不是空行,这行就不起作用,于是继续处理第9行。b命令除了可以跳出本次处理以外,还可以指定跳转的位置,比如上文中使用:标记的top
第9行:使用s替换命令取出行中RX bytes:字符之后的所有数字。这里本身并没有分支判断,分支判断出现在下一行
第10行:T命令是一个逻辑判断指令。它的含义是,如果前面出现的s替换指令没有找到符合条件的行,则跳转到T后面所指定的标记位置。在这里的标记位置为top,是我们在上面使用:标记出来的位置。就是说,如果上面的s替换找不到RX bytes:关键字的行,那么就执行过程会跳回top位置继续执行,就是接着再看下一行进行检查
在这里,我们实际上是用了冒号标签和T指令构成了一个循环。当条件是s替换找不到指定行的时候,就继续执行本循环,直到找到为止。找到之后就不会再跳回top位置了,而是继续执行第11行
第11行:H指令,意思是将当前模式空间中的内容追加进保存空间。当前模式空间已经由s替换指令处理成只保留了接受的字节数。之前的保存空间中已经存了网卡名,追加进字节数之后,保存空间里的内容将由两行构成,第一行是网卡名,第二行是接收字节数。注意h和H指令的区别,h是将当前模式空间中的内容保存进保存空间,这样做会使保存空间中的原有内容丢失。而H是将模式空间内容追加进保存空间,保存空间中的原来内容还在
此时保存空间中已经存有我们所有想要的内容了,网卡名和接收字节数。它们是放在两行存的,这仍然不是我们想要的结果,我们希望能够在一行中显示,并用冒号分隔。所以下面要做的是替换,将换行替换成冒号。但是我们不能直接操作保存空间中的内容,所以需要将保存空间的内容拿回模式空间才能操作
第12行:x指令,意思是将模式空间内容和保存空间内容互换。互换之后,网卡和接收字节数就回到模式空间了。然后我们可以使用s指令对模式空间内容做替换
第13行:s/\n/:/g,将换行替换成冒号。之后模式空间中的内容就是我们真正想要的“网卡名:接收字节数”了。于是就可以p打印或者使用w指令,保存模式空间内容到某个文件中
所有指令的退出条件有两个:
第8行,遇到空格之后本段解析结束。
所有指令执行完,打印或保存了相关信息之后执行完。
执行完退出后,sed会接着找下一个网卡信息开始的段,继续下一个网卡的解析操作,这就是这个复杂sed命令的整体处理过程
更多资料:
http://sed.sourceforge.net/sed1line_zh-CN.html
http://zuyunfei.com/2015/07/13/sed-in-shell-3/