Chinaunix首页 | 论坛 | 博客
  • 博客访问: 134254
  • 博文数量: 28
  • 博客积分: 527
  • 博客等级: 中士
  • 技术积分: 367
  • 用 户 组: 普通用户
  • 注册时间: 2011-02-09 17:05
个人简介

运维开发工程师。致力于网络,WEB应用服务,Linux系统运维。方向:操作系统,监控,自动化

文章分类

全部博文(28)

文章存档

2013年(12)

2012年(16)

分类: Python/Ruby

2012-11-19 11:18:19

Intro
sed是一款精简、强大的流编辑器(stream editor),对文本行进行查找、更新替换、插入删除等操作,支持BRE正则。


sed工作模式
sed如何工作
sed是一种在线编辑器,它一次处理一行内容。处理时:
  1. 把当前处理的行读入临时缓冲区,称为“模式空间”(pattern space);
  2. (如果提供-e选项)用每一个sed命令依次处理缓冲区中的内容;
  3. 处理完成后,把缓冲区的内容送往屏幕。
  4. 回到1,接着处理下一行,这样不断重复,直到文件末尾。
  • Copy the input line into the pattern space.
  • Apply the first sed command on the pattern space, if the address restriction is true.
  • Repeat with the next sed expression, again operating on the pattern space.
  • When the last operation is performed, write out the pattern space and read in the next line from the input file.
文件内容并没有改变,除非指定-i选项。sed主要用来自动编辑一个或多个文件;简化对文件的反复操作;编写转换程序等。


sed基本语法
  1. sed [options] 'sed_command' file
  2. sed [options] -e 'command1' -e 'command2' file #当有多个sed编辑命令时,分别用-e引开:
  3. sed [options] -f sed_script_file file #当把sed指令集中放在文本文件中时,可以用-f来引用sed脚本。
  4. 'sed_command'又可以细分为:'addresscommand1command2command3',即“定位+指令”的形式。(定位和指令们之间可以忽略空格字符)
  5. sed [options] 'sed_command' - #进入“交互型”模式,从标准输入-读入


sed寻址
在讲具体实例前,简要谈谈sed的寻址。由于sed是基于行的编辑器,可以通过定址来定位所希望编辑的行(文本域)。文本域(地址)范围可以通过数据,正则表达式或者二者结合的方式确定:
  1. n
  2. n,m
  3. /reg1/,/reg2/
  4. /reg/,m
  5. n,m! #不在这个范围内
最普通的地址用数字构成,用逗号分隔的两个行数n,m表示以这两行为起止的行的范围(包括行数表示的那两行)。如1,3表示第1,2,3行,3,$表示从第三行到最后一行的文本域。美元符号($)表示最后一行。
在地址后加!,代表不在这个范围内。


sed默认行为
1.默认打印
sed默认会输出所有读入模式空间并处理过的文本行(哪怕未被处理过的文本行)。
  1. $ sed '/soul/p' plain.txt 
  2. before my time
  3. as my soul heals the shame
  4. as my soul heals the shame
  5. ..
这句打印文件,p会再一次输出带有soul的行;

2. 禁止打印-n和指定输出被处理的行-n,p
因此时常我们要屏蔽这些annoying的输出,用-n选项,屏蔽输出。
经常地,-n和p指令会同时出现,这样可以输出被真正处理过的文本行。
  1. $ sed -n '/soul/p' plain.txt
  2. as my soul heals the shame 

sed修改文件
一般情况下,sed不会修改输入源文件,默认标准输出。若要完成文件修改(生成),可以:
1. shell IO重定向
  1. sed '/man/d' < plain.txt > result.txt #把delete后的行写入result.txt
2. 选项-i修改源文件,操作比较危险,谨慎
  1. sed -i '/need/NEED/g' result.txt #修改result,执行替换操作
3. 指令w
  1. sed -n '1,2w filename' plain.txt #将plain.txt的1,2行写入 filename文件。
sed打印
指令p(结合寻址讲解)
1. 输出文件,同cat
  1. $ sed '' plain.txt    #利用默认输出行为
  2. $ sed -n '1,$p' plain.txt #等价
2. 输出第n行的文本
  1. $ sed -n '4p' plain.txt #打印第4行
  2. in pouring rain
3. 输出第n到m行的文本,特别的,$代表末行
  1. $ sed -n '9,11p' plain.txt #打印第9到11行
  2. as my soul heals the shame 
  3. i will grow through this pain 
  4. lord i''''m doing all i can 
  5. ----------------------------
  6. $ sed -n '1,$p' plain.txt #同cat,全文打印
4. 输出带有soul到带有开头lord的文本行
  1. $ sed -n '/soul/,/^lord/p' plain.txt       
  2. as my soul heals the shame 
  3. i will grow through this pain 
  4. lord i''''m doing all i can 
  5. ----------------------------
  6. $ sed -n '/doing/,$p' plain.txt  #行号、正则两者混用
  7. lord i''''m doing all i can 
  8. to be a better man 

sed删除
指令d
1. 删除第n,m行的文本
  1. $ sed '1,5d' text.txt  #删除1-5行
  2. in pouring rain

sed替换
指令s, s/regex_pattern/string_replacement/,分隔符"/"可以是任意其他字符。默认替换第一个,加g参数后sed全局替换(特别的,g换成数字即替换第n个出现的字段)。sed支持BRE+GNU正则,不支持ERE
1. 替换
  1. $ sed 's/me/ME/' plain.txt #全文替换并打印
  2. send soMEone to love me 
  3. i need to rest in arms 
  4. keep ME safe from harm 
  5. ..,
  6. -----------------------------
  7. $ sed -n '1,$s/me/ME/p' plain.txt  #替换的部分打印,此处s,p命令联合,1,$可以忽略。
  8. send soMEone to love me 
  9. keep ME safe from harm 
  10. give ME endless summer 
  11. before my tiME 
  12. as my soul heals the shaME
  13. ------------------------------
  14. sed -n 's/me/ME/gp' plain.txt  #加g参数后sed全局替换,默认替换第一个
  15. send soMEone to love ME 
  16. keep ME safe from harm 
  17. give ME endless sumMEr 
  18. before my tiME 
  19. as my soul heals the shaME 
  20. -----------------------------
  21. sed -i 's/me/ME/g' plain.txt  #全局替换并修改源文件
  22. -----------------------------
  23. sed -n 's/me/ME/gpw a.txt' plain.txt  #替换后写入文件a.txt


更多sed替换正则例子
此处仅使用正则,将会在另一篇内详细讨论正则表达式。
1. 变换分隔符,当某些情况下需要频繁转义regex和replacement字串时,考虑换一个分隔符;
  1. find /home/work -type d | sed 's#/home/work/#/home/rd/#' #将/home/work路径替换为/home/rd,等价于sed 's/\/home\/work\//\/home\/rd\//'
2. 删除字段,用空字符来替换匹配的部分,达到删除的目的;后向引用
  1. sed -n 's/\([a-z]\)\1//gp' plain.txt #用到了后向引用,匹配重复2次出现的字母,并删除
  2. i nd to rest in arms
  3. kp me safe from harm
  4. give me endle suer
  5. fl i''''m geing old
  6. i wi grow through this pain
  7. lord i''''m doing a i can
  8. to be a beer man
3. 插入字符;
  1. sed -n 's/^\(lord\)/Oh \1/gp' plain.txt
  2. Oh lord i fear the cold
  3. Oh lord i''''m doing all i can
4. 引用匹配的regex,&符号;
  1. sed 's/ar/|&|/' plain.txt
  2. i need to rest in |ar|ms
  3. keep me safe from h|ar|m
5. 使用空的正则;
  1. sed -e 's/e/|E|/2' -e 's//{E}/' plain.txt #第二个空正则使用了第一个已经使用了正则/e/,先替换第二个e,在替换第一个e
  2. i n{E}|E|d to rest in arms
  3. k{E}|E|p me safe from harm
6. 贪婪的正则:正则表达式默认贪婪,总是匹配最长的字串;
  1. echo "i need to rest in arms " | sed 's/i.*e//' #匹配了最长的"i need to re"而非"i ne"
  2. st in arms
7. 匹配重复字符:\{n,[m]\}
  1. sed -n 's/e\{2,\}/X/p' plain.txt
  2. i nXd to rest in arms
  3. kXp me safe from harm
  4. fXl i''''m getting old
8.  扩展正则,单词字符([[:alnum:]_] == \w),单词锚点\b
  1. sed -n 's/\b\(\w\)/\U\1/gp' plain.txt #把每个单词的首字符大写
  2. Send Someone To Love Me
  3. I Need To Rest In Arms
  4. ...


sed行后追加
指令a\string,当多行时要追加\
1. 默认在每一行后另起追加string内容
  1. $ sed 'a\???' plain.txt #每一行后追加
  2. send someone to love me 
  3. ???
  4. i need to rest in arms 
  5. ???
  6. keep m
  7. ---------------------------------
  8. $ sed '3a\yes\
  9. or\
  10. no' plain.txt #第三行后追加yes\nor\no
  11. keep me safe from harm 
  12. yes
  13. or
  14. no
2. 在最后一行后加一行作者
  1. $ sed '$a\Author : Zzr' plain.txt #追加
  2. to be a better man 
  3. Author : Zzr
指令r filename:将filename文件读入并附加到addr的后一行,等效a\string
  1. $ sed '4r standardio.sh' plain.txt
  2. keep me safe from harm
  3. in pouring rain
  4. #!/bin/bash
  5. tr -d 'e' < subprocess.sh


sed行前插入
指令i\string
1. 默认在每一行前另起插入string内容
  1. sed 'i\string' plain.txt  #每一行后追加
  2. string
  3. send someone to love me 
  4. string
  5. i need to rest in arms 
2. 在第一行前加日期
  1. $ sed '1i\Date : 20121215' plain.txt     #在第一行前加日期    
  2. Date : 20121215


sed当前行修改
指令c\string
1. 默认修改为每一行的内容为string
  1. sed 'c\string' plain.txt   #每一行修改为string
  2. string
  3. string
  4. string
2. 在my出现的地方标记为HAVE A MY.
  1. sed '/my/c\HAVE A MY' plain.txt     #
  2. ...
  3. feel i''''m getting old 
  4. HAVE MY
  5. HAVE MY
  6. i will grow through this pain

sed字符映射替换
指令y/char_set1/char_set2/
1. 功能和tr类似,将char_set1里的每个字符依次映射到char_set2的字符集
  1. $ sed 'y/aeiou/AEIOU/' plain.txt #a->A,e->E,i->I,o->O,u->U
  2. sEnd sOmEOnE tO lOvE mE 
  3. I nEEd tO rEst In Arms 
  4. kEEp mE sAfE frOm hArm 
  5. ---------------------------------
  6. tr 'aeiou' 'AEIOU' < plain.txt #等价

sed退出
指令q
1. 只要到q,立即退出sed程序
  1. $ sed 'Nq' plain.txt  #到第N行就退出
  2. $ sed -n '1,Np' plain.txt #等效
  3. $ head -n N plain.txt #等效
  4. ----------------------------
  5.      1  send someone to love me 
  6.      2  i need to rest in arms 
  7.      3  keep me safe from harm 

sed多行命令
选项e,编辑命令的顺序会影响结果

  1. sed -e '1,5d' -e 's/me/ME/' plain.txt #先删行,再替换
  2. -------------------------------
  3. lord i fear the cold
  4. feel i''''m getting old
  5. before my tiME
  6. as my soul heals the shaME
  7. i will grow through this pain
  8. lord i''''m doing all i can
  9. to be a better man

sed引用shell变量
  1. 方法1:用""取代'',在sed的命令行中引用shell变量时要使用双引号,而不是通常所用的单引号。
  2. $ var=ME
  3. $ sed -n "1,5s/me/$var/gp" plain.txt
  4. send soMEone to love ME
  5. keep ME safe from harm
  6. give ME endless sumMEr
  7. -----------------------------------------
  8. 方法2:用'$var'的形式引用
  9. $ sed -n ‘1,5s/me/’$var‘/gp’ plain.txt #等价形式

参考资料
http://firesk.blog.51cto.com/180373/212875
http://www.cnblogs.com/edwardlost/archive/2010/09/17/1829145.html


附:测试文件
send someone to love me 
i need to rest in arms 
keep me safe from harm 
in pouring rain 
give me endless summer 
lord i fear the cold 
feel i''''m getting old 
before my time 
as my soul heals the shame 
i will grow through this pain 
lord i''''m doing all i can 
to be a better man

阅读(1343) | 评论(0) | 转发(0) |
0

上一篇:没有了

下一篇:Tomcat启停脚本实现

给主人留下些什么吧!~~