最有用系列:python
《Linux生产环境上,最经常使用的一套“vim“技巧》编程
《Linux生产环境上,最经常使用的一套“Sed“技巧》vim
《Linux生产环境上,最经常使用的一套“AWK“技巧》bash
《"Sed" 高级功能:我这小脑瓜都快绕晕了》markdown
sed命令有两个空间,一个叫pattern space,一个叫hold space。这两个空间可以证实人类的脑瓜容量是很是小的,须要通过大量的训练和烧脑的理解,才能适应一些很是简单的操做。编程语言
不信看下面简单的命令,做用是,删除文件中最后两行。编辑器
sed 'N; $!P;$!D;$d' file 复制代码
在《Linux生产环境上,最经常使用的一套“Sed“技巧》一文中,咱们介绍了经常使用的sed命令和操做,并且使用了两张图来做为辅助。但惋惜的是,这两张图,严格来讲是不许确的 (好比s命令,只是其中的一个子集),即便它可以帮助初学者快速入门。oop
本篇属于sed的中级用法,常见在一些sed脚本中,在平常中应用并很少,但每每可以得到意想不到的效果。post
这要从sed的工做模式来讲起。测试
with open('file', 'r') as f: for line in f.readlines(): print(line) 复制代码
sed命令在这之上,还缓冲了另一个东西。那就是“上一行的内容” ,叫作hold space。而当前行,叫作patter space。用python简单表现一下:
hold_space = "" with open('file', 'r') as f: for pattern_space in f.readlines(): print(hold_space,pattern_space) hold_space = pattern_space 复制代码
具体过程,大致与上面的代码相似,以上面的图为例。在这个例子中,hold space不参与运算,是全程无感的:
一、 读取当前行
wtf..
到 Pattern space二、 执行命令
p
,这会打印出当前行三、 把Pattern space的内容,赋值给Hold space
四、 继续下一行的处理,循环这个过程
但我想稍微操做一下这两个缓冲区。这个操做就是swap,使用x表示,这也是一些文本编辑器的一向尿性。
也就是,在p以前,咱们加上了个x。表示先将这两个缓冲区进行置换,而后再往下走。
hold_space = "" with open('file', 'r') as f: for pattern_space in f.readlines(): swap(hold_space,pattern_space) print(hold_space,pattern_space) hold_space = pattern_space 复制代码
让我咱们来想象一下这个过程。
一、 刚开始,hold_space的内容是空。然鹅,还没被填充,它就被使用了,和当前行进行了置换
二、 p命令用在了置换后的缓冲区上,第一次打印出了空行,fuck
三、 继续嘟嘟嘟,如今到了最后一行,立刻进行了置换,没机会打印就到了hold_space中了
四、 当前行,存放的是倒数第二行的数据,最后一行见光死,就永远没有机会面世了
咱们固然有办法把它搞出来,好比,我执行偶数次的交换x。
sed -n 'x;x;x;x;p' file 复制代码
有木有一股骑着羊驼走天下的的感受?
你可能会想,我对这两个缓冲区交换,有什么用?接下来看这个文件。
小姐姐味道公众号
CEO
加菲猫经理
IT Manager
系统毁灭师
Sysadmin
小哥哥味道
Developer
爱卖东西的经理
Sales Manager
风清扬
Dog
复制代码
文件奇数行是名称,偶数行是职位。咱们想要输出全部Manager
的名字。就可使用下面的命令。
sed -n -e 'x;n' -e '/Manager/{x;p}' file 复制代码
命令分为两个部分。
x;n
表示将偶数行保存在pattern space,那么奇数行就保存在hold space中。
/Manager/{x;p}
命令将在pattern space上执行对Manager关键字的查找。若是符合条件,则再次交换p和h缓冲区,输出奇数行对应的名字。
上面的x
和n
,就是针对这两个缓冲区的命令。这样的命令有不少。
这些命令,若是多了,可使用{}包围起来,就像上面的命令同样。这些命令的位置与咱们上一篇所说的,在同一个地方。
x 请允许我用英文装个b:Exchange the contents of the hold and pattern spaces.
d 清空当前的pattern space,而后进入下一个循环
D 删除pattern space的第一行(multiline pattern)
h 复制pattern space到hold space
H 追加pattern spaced到hold space
g 复制hold space到pattern space
G 追加hold space到pattern space
n 读取下一个输入行到pattern space
N 追加下一个输入行到pattern space,同时将两行看作一行,可是两行之间依然含有\n换行符
p 打印当前的pattern space
P 打印当前的pattern space中的第一行
上次提到的推箱子游戏,就用了不少这种东西。为了使使用者在书写sed脚本的时候真正的"自由",sed还容许在脚本中用":"设置记号。标签,有种相似编程语言的特性了。
q 退出sed,能够增长执行速度
l 列出当前行,包含不可打印字符
l width 列出当前行,使用一个
width characters
结尾b label 跳到相应的标签,分之命令。
t label if分支,从最后一行开始,条件一旦知足或者T,t命令,将致使分支到带有标号的命令处,或者到脚本的末尾。测试命令。
T label 错误分支,从最后一行开始,一旦发生错误或者T,t命令,将致使分支到带有标号的命令处,或者到脚本的末尾。
固然还有其余更不经常使用的,可使用man命令查看
man sed
复制代码
看着一行行进行处理,好像很简单是否是?不可能的,看下面几个简单的命令,训练一下生锈的脑子。
一个流水线同样的命令
sed -n '2{h;n;x;H;x};p' file 复制代码
交换第2行和第3行的内容
输出最后一行
sed 'N;D' file 复制代码
输出文件中最后两行
sed '$!N; $!D' file 复制代码
删除文件中最后两行
sed 'N; $!P;$!D;$d' file 复制代码
打印偶数行的另外一种写法
sed –n 'n;p' file 复制代码
每隔5行加入一个空行。
sed 'n;n;n;n;G' file 复制代码
输出含AAA和BBB和CCC(任意顺序)的段落
sed -e '/./{H; $!d;}' -e 'x;/AAA/!d; /BBB/!d; /CCC/!d' file 复制代码
颠倒行序(使末行变首行,首行变末行)
sed -n '1!G; h; $p' file 复制代码
这个命令有点绕,首先,
1!G
对除了第一行的其余行进行了G操做,而后反向复制回去,到了最后一行,就直接打印Pattern Space。$
表示到了最后一行执行下面的命令,也能够是${p}
一个带标签的用法
sed -e :a -e '$q;N;11,$D;ba' 复制代码
打印最后10行。a
是标签。语法就是单独的行,使用:
分隔。
为了提升你在公司的竞争力,你是能够弄一堆sed脚本唬人(埋雷)的。和某些perl脚本同样,即便是有相关经验的开发着,理解起来也要下点功夫,就不要说其余人了。
这就是sed,简约但不简单的命令,本文算是一个中级入门。中级入门也有点烧脑,由于你的脑瓜里,须要一直维护着这两个缓冲区。又是置换,又是清空,至关于人肉状态机。固然,怎么把这个过程讲的尽可能简单一点,仍是浪费了做者很多脑细胞的。哪怕你点个赞,也是延缓小姐姐走向老年痴呆时间的一个途径。有了你的支持,小姐姐也能够想点技术以外的事情,好比喷喷bat什么的。