sed的流艺术

本文章参考《Linux大棚命令百篇》,推荐买着看,很好的一本书。

sed (stream editor)被称之为流编辑器。
sed命令是针对于行处理的工具,对每一行进行处理,并将处理的结果输出到标准输出。

sed的命令格式:

sed  command file

command部分:针对每行的内容要进行的处理
 file部分:要处理的文件,如果忽略file参数,则sed会把标准输入作为处理对象。

sed的工作原理:
sed会一次处理一行内容。处理时,把当前处理的行存储在临时缓冲区中,称为“模式空间”(pattern space),接着用sed命令处理缓冲区中的内容,处理完成后,把缓冲区的内容送往屏幕。接着处理下一行,这样不断重复,直到文件末尾。文件内容并没有改变,除非你使用重定向存储输出

一个简单的栗子:

# cat  example.txt 
test 1
test2
testtest
XtestX
BBtest

# sed  '/2/d'  example.txt 
test 1
testtest
XtestX
BBtest

这个栗子是删除文件中包含字符"2"的行。命令要用单引号括起来!

/2/d中的d表示删除,意思就是说只要某行含有字符2,则删除之。

想实现类似于cut -d : -f 1 /etc/passwd的效果,用sed怎么做呢?

# head -n 5 /etc/passwd 
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
adm:x:3:4:adm:/var/adm:/sbin/nologin
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin


# head -n 5 /etc/passwd | sed  's/:.*$//' 
root
bin
daemon
adm
lp

一些命令

sed会将模式空间里的行经过处理后输出到标准输出,这是默认的处理方式。就是说,除非你使用d命令来删除此行,否则它无论变成什么样子,无论它被替换成什么形状,它都会多多少少被输出到屏幕上。

-n选项一般会和-p配合使用,意思是输出那些匹配到的行。

# cat  example.txt                 
test 1
test2
testtest
XtestX
BBtest

# sed -n   '/test2/p'  example.txt 
test2

sed的command部分可以分为两块:一块是范围设定,一块是动作处理。
范围设定可以采用两种不同的方式来表达:

  • 指定行数:比如'3,5',表示第3行,4行,5行;而'5,$'表示第5行至文件最后一行。
  • 匹配模式:例如/[dD]/表示匹配行首不是以d或D开头的行等等。

动作部分:

  • d:表示删除行

  • p:打印该行

  • r:读取指定文件的内容

  • w:写入指定文件

  • a:在下面插入新行新内容

看一下例子吧:

显示文件的第10到20行:
# sed -n '10,20p' example.txt 
vfinj
VBFNJ
VFEANKM
VREF
VERFD
 VF
 BTERS F
 3RQEVAF
 BQTAW SV
 Qreafd
 qVWAD 

将所有以V或v开头的行的所有小写n变为大写N
# sed  '/^[vv]/s/n/N/g'  example.txt 

我们在command命令部分采用 /AA/s/BB/CC/g 的语法,这表示我们要匹配到文件中带有AA的行,并且将这些行中的BB替换成CC。

删除每行最后两个字符:
# sed  's/..$//'  example.txt  

删除每一行的前两个字符:
# sed ‘s/..//’ test

&符号的妙用:
&表示“被匹配的部分”

# cat  mysed.txt 
Beijing
London

# sed 's/Bei/&2008/'  mysed.txt 
Bei2008jing
London

更好的定位方法:

# cat mysed.txt  
Beijing 2003
Beijing 2004
Beijing 2005
Beijing 2006
Beijing 2007
Beijing 2008
Beijing 2007


# sed  -n '/2005/,/2007/p' mysed.txt 
Beijing 2005
Beijing 2006
Beijing 2007

我们使用/2005/来匹配行范围的首行,用/2008/来匹配行范围的最尾行。可以看到,在匹配尾行时,只要遇到符合要求的行,即停止,不会再继续向后匹配了。(只是匹配到第一个2007,并没有匹配到第二个2007)

使用-e选项来设置多个command:
当包含超过一个的command的时候,必须在每个command前面加上选项-e

# sed  -n  -e '1,2p' -e '4p' mysed.txt 
Beijing 2003
Beijing 2004
Beijing 2006

注意:-e后面必须立即接command,不允许再夹杂其他的选项

使用 -f指定command文件:
如果你的command很长,那么可以将其写在文件里,然后使用-f来设定这个文件作为command部分:

# cat callsed 
/2004/,/2006/p

# sed -n -f callsed   mysed.txt 
Beijing 2004
Beijing 2005
Beijing 2006

插入和控制

在多个command之间,是按照在命令中的先后顺序来执行的。

插入内容:

将要插入的内容保存到一个单独的文件
$ cat ins.txt
====China====

使用r 实现插入
sed ‘/2005/r ins.txt’ mysed.txt

除了可以通过指定文件来插入外,还可以使用 'a'在特定行的下面插入特定内容:

# sed '/2004/a\china'  mysed.txt 
Beijing 2003
Beijing 2004
china
Beijing 2005
Beijing 2006
Beijing 2007
Beijing 2008
Beijing 2007

还可以使用 '\i'在指定行的上面添加内容:

# sed '/2004/i\china'  mysed.txt  
Beijing 2003
china
Beijing 2004
Beijing 2005
Beijing 2006
Beijing 2007
Beijing 2008
Beijing 2007

y动作:
y就是按照字符顺序,实现前后的替换

# sed  'y/ei/ie/'  mysed.txt 
Biejeng 2003
Biejeng 2004
Biejeng 2005
Biejeng 2006
Biejeng 2007
Biejeng 2008
Biejeng 2007

y的语法格式: y/source/dest/
如果source中出现了重复的字符,则只有第一次对应的替换会产生效果,后面的不会起作用。

原文
# cat mysed.txt 
Beijing 2003
Beijing 2004
Beijing 2005
Beijing 2006
Beijing 2007
Beijing 2008
Beijing 2007

在iji到iba的替换中,只有j到b起到了作用
# sed  'y/iji/iba/' mysed.txt 
Beibing 2003
Beibing 2004
Beibing 2005
Beibing 2006
Beibing 2007
Beibing 2008
Beibing 2007

对匹配行的下一行进行处理:

# sed '/2004/{n;y/eijing/EIJING/;}'  mysed.txt 
Beijing 2003
Beijing 2004
BEIJING 2005
Beijing 2006
Beijing 2007
Beijing 2008
Beijing 2007

这个例子就是找含有2004的行,然后将它下面的一行中的eijng替换为大写的EIJNG。这里面的“n;”起到了“移至下一行”的作用。n背后的含义其实是将下一行放到模式空间中去。

将指定行写入到指定文件中:
w动作会将匹配到的内容保存到另一个文件中:

# sed '/200[4-6]/w  new.txt'  mysed.txt

# cat  new.txt 
Beijing 2004
Beijing 2005
Beijing 2006

如果想在原文件中进行操作,需要加 -i 选项。

你可能感兴趣的:(sed的流艺术)