Xiaowo

I Lay My Love On You~

linux小记:恍然大明白,sed命令中[commands]的格式

sed是我在linux上最喜欢的命令之一!(其实我很想说sed说是我最喜欢的命令,不过linux我喜欢的逆天的命令实在是太多了,所以sed就是其中“之一”了吧。)

之前一直觉得sed的格式乱乱的,又是sed '1,2p' fileName,又是sed 's/old/new/g' fileName的,格式千差万别,毫无规律可循!直到今天看到了这篇文章,终于看到了统一点!

sed的用法就是:

sed [options] [commands] [input-file]

options就是带杠的参数,input-file就是文件的名字,关键在于commands!

不过commands也是有固定格式的:

[范围][指令]

关键在于[range]和[command]格式都比较丰富,所以组合起来才显得比较乱。

范围

先来说说范围!

最简单的范围莫过于——
‘m,n’表示从m行到n行: sed '2,3p' fileName,指处理2~3行;
‘m,+n’表示从m行到m+n行: sed '2,+3p' fileName,指处理2~(2+3=5)行。
‘m~n’表示从m行开始每n行匹配一次: 如1~2表示只匹配奇数行,2~2表示只匹配偶数行。
特殊符号包括:$表示最后一行;0表示第一行前,也就是最开始;匹配后加!表示不匹配以上条件的行(类似取反)。如sed '1~2d' file #删除奇数行sed '1~2!d' file #删除偶数行

复杂一点的范围——
使用正则表达式匹配范围:'3,/hello/'指的是从第3行到第一次出现hello的行的这一部分。比如sed '3,/hello/d' fileName指删除3~”第一次出现hello的行”。sed -n '/test/,/check/p' fileName指打印test到check的行。

正式因为这些匹配的方式多样,导致他们和命令组合起来之后显得比较多变。

指令

比较简单的指令也比较好看懂——
比如d,和前面的范围组合起来之后,简单的就是sed '2,5d' fileName,删除2~5行;稍复杂点儿就是sed '2,/hello/d',删除2~“第一次出现hello的行”。

复杂的指令和之前的范围组合起来就不容易看懂了——
比如ss是个自带一大串参数的指令,也是用的最多的指令。其格式为s/oldString/newString/flags,那么和前面的范围组合起来就把commands这一块儿变成了:[range]s/oldString/newString/[flags]
这样的话整个sed命令就变成了:

sed [options] '[range]s/oldString/newString/[flags]' [filename]

比如sed '2,$s/hi/hello/g' fileName表示从第二行到最后一行,将所有的hi替换成hello。

如果[范围]再复杂一点儿,变成sed '2,/haha/s/hi/hello/g' fileName,表示从第二行到第一次出现haha的行,将所有的hi替换为hello;sed '/haha/s/hi/hello/g'表示将所有含有haha的行的所有hi替换为hello。

这样只要知道sed命令中间的commands部分由范围和指令组成,在分别搞懂了这两部分的形式,他们再组合起来就不显得混乱了。

一些知识点

-ibak

sed的-i命令是覆盖源文件,以后建议使用-ibak,比如sed '2,+8d' hello.txt,在删除hello.txt文件的2~10行之前,会先生成一个名为hello.txtbak的备份文件,有备份总是好事儿,大不了再手动删一次,总比sed命令改坏了源文件欲哭无泪强!

-np

p一般都是和-n同时出现,可以起到只显示被处理的行的效果。
比如,对于DreamList.puppy文件,原内容为:

lgl@pArch ~/tmp/sed $ cat DreamList.puppy 
Drm Lst wth Pppy
- S th srs
- Slf-stdy  MB
- Tk phts rd MB
- St sd th lk f r rd d tlk dr sst
- t brkfst vry dy, lch vry dy, dr vry dy
- R  th plyrd d Strtch th bds ftr tht
- Wtch mvs
- Wt tsd th rl's drmtry
-  t hr wrkplc t wt hr t ff dty
- Rd tsd th cmps
- Wtch xhbts sh hs trsts 
- Sy  LV Y vry dy vry mmt
- t FST, FST, FST f r w
- Mk ... r... Prdc LV

进行替换处理,将所有出现S的行的小横杠换成五个#:

lgl@pArch ~/tmp/sed $ sed '/S/s/-/#####/g' DreamList.puppy    
Drm Lst wth Pppy
##### S th srs
##### Slf#####stdy  MB
- Tk phts rd MB
##### St sd th lk f r rd d tlk dr sst
- t brkfst vry dy, lch vry dy, dr vry dy
##### R  th plyrd d Strtch th bds ftr tht
- Wtch mvs
- Wt tsd th rl's drmtry
-  t hr wrkplc t wt hr t ff dty
- Rd tsd th cmps
- Wtch xhbts sh hs trsts 
##### Sy  LV Y vry dy vry mmt
##### t FST, FST, FST f r w
- Mk ... r... Prdc LV

可以看到不管处理没处理的行都打印出来了。
如果使用p-n的组合:

lgl@pArch ~/tmp/sed $ sed -n '/S/s/-/#####/gp' DreamList.puppy
##### S th srs
##### Slf#####stdy  MB
##### St sd th lk f r rd d tlk dr sst
##### R  th plyrd d Strtch th bds ftr tht
##### Sy  LV Y vry dy vry mmt
##### t FST, FST, FST f r w

可以看到只有被处理的行被显示了。

命令和flags

刚刚说到s命令最后可以有flags,其中flags和命令很多都是一模一样的。这里提一下防止搞晕。
例如:
sed '2,3p' fileName为打印2~3行,这里的p是和s同级别的命令。
sed '2,3s/hi/hello/gp',这里的p属于s命令的flags,是s命令的一部分。

连续使用sed

连续使用sed命令需要使用-e参数:

sed -e [command1] -e [commaned2]... [inputfile]

sed -i -e G -e 's/^-/#####/g' fileName为先在每一行后面添加空行,再将所有开头的’-‘替换为’#####’。

其实连续使用sed还可以使用;。以上命令等价于:
sed -i '{G;s/^-/#####/g}' fileName或者sed -i 'G;s/^-/#####/g' fileName

奇偶行与n

上面我们说范围匹配的时候提到过奇偶行。
sed '1~2d' file #删除奇数行
sed '1~2!d' file #删除偶数行
sed '2~2d' file #删除偶数行

也可以用n(不是-n)实现同样的效果:
sed 'n;d' file删除偶数行
sed '1d;n;d' file删除奇数行

缓冲区

想明白上面的nG的用法,需要涉及到缓冲区。

sed处理问本行的步骤:

  • 读取一行到模式空间缓冲区
  • 按照命令对模式空间缓冲区内容进行处理
  • 打印处理后缓冲区中的文本
  • 循环到第一步读取下一行,直到文本处理完

临时缓冲区、n

每一行都被保存在一个叫模式空间的临时缓冲区中,除非行被删除或者输出被取消,否则所有被处理的行都将打印在屏幕上,接着模式空间被清空。

所以sed 'n;d' file删除偶数行,可以解释为:sed开始读了第一行到缓冲区,然后执行n,意味再读一行,所以就读了第二行,然后执行d,于是第二行被删除了。以此类推,所有的偶数行都被删除了。

n N Read/append the next line of input into the pattern space.

保持缓冲区、hG

hg是互逆的过程,其中消协代表拷贝,大写代表添加。

h H Copy/append pattern space to hold space.
g G Copy/append hold space to pattern space.

我们先来看一个命令:
sed -e '/test/h' -e '$G' file
在这个例子里,匹配test的行被找到后,将存入模式空间(临时缓冲区),h命令将其复制并存入一个称为保持缓存区的特殊缓冲区内,保持缓冲区如果不使用G取出,将会一直存在(所以叫“保持”缓冲区,而不是“临时”缓冲区)。

第二条语句的意思是,当到达最后一行后,G命令取出保持缓冲区的行,然后把它放回模式空间中,且追加到现在已经存在于模式空间中的行的末尾。在这个例子中就是追加到最后一行。简单来说,任何包含test的行都被复制并追加到该文件的末尾。

看了这我们就知道为什么sed G fileName能够在每一行后面添加一个空行了。因为保持缓冲区中没有内容,G就只能取到空内容。每次sed取一行文本到临时缓冲区,G就在保持缓冲区中取空内容添加到这一行后面,也就是在这行后面添加了一个空行,以此类推,所有行后面都被追加了一个空行。

x

x Exchange the contents of the hold and pattern spaces.

这个时候我们再看x命令就不难理解了。x表示互换临时缓冲区和保持缓冲区的内容。

所以看这个命令:

lgl@pArch ~ $ seq 3
1
2
3
lgl@pArch ~ $ seq 5 | sed 'x'

1
2
3
4
lgl@pArch ~ $ 

刚开始hold space是空的,1和空行交换,1进入了hold space,空行进入了pattern space,输出空行,接下来1和2交换,2进入hold space,1换到了pattern space,输出。一直到最后,5被换如了hold space。所以只打印了空行和1~4。

阅读更多
版权声明:本文为博主原创文章,欢迎转载欢迎传播,注不注明出处随你,只要对更多人有所帮助就行。 https://blog.csdn.net/puppylpg/article/details/51591648
文章标签: linux sed
个人分类: linux
想对作者说点什么? 我来说一句

Unix/Linux sed命令手册

2007年08月13日 160KB 下载

sed-4.2.1.tar.bz2

2014年07月02日 878KB 下载

sed命令大全

2018年01月20日 445KB 下载

没有更多推荐了,返回首页

加入CSDN,享受更精准的内容推荐,与500万程序员共同成长!
关闭
关闭