Intro
sed是一款精简、强大的流编辑器(stream editor),对文本行进行查找、更新替换、插入删除等操作,支持BRE正则。
sed工作模式
sed如何工作
sed是一种在线编辑器,它一次处理一行内容。处理时:
-
把当前处理的行读入临时缓冲区,称为“模式空间”(pattern space);
-
(如果提供-e选项)用每一个sed命令依次处理缓冲区中的内容;
-
处理完成后,把缓冲区的内容送往屏幕。
-
回到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基本语法
-
sed [options] 'sed_command' file
-
sed [options] -e 'command1' -e 'command2' file #当有多个sed编辑命令时,分别用-e引开:
-
sed [options] -f sed_script_file file #当把sed指令集中放在文本文件中时,可以用-f来引用sed脚本。
-
'sed_command'又可以细分为:'addresscommand1command2command3',即“定位+指令”的形式。(定位和指令们之间可以忽略空格字符)
-
sed [options] 'sed_command' - #进入“交互型”模式,从标准输入-读入
sed寻址
在讲具体实例前,简要谈谈sed的寻址。由于sed是基于行的编辑器,可以通过定址来定位所希望编辑的行(文本域)。文本域(地址)范围可以通过数据,正则表达式或者二者结合的方式确定:
-
n
-
n,m
-
/reg1/,/reg2/
-
/reg/,m
-
n,m! #不在这个范围内
最普通的地址用数字构成,用逗号分隔的两个行数n,m表示以这两行为起止的行的范围(包括行数表示的那两行)。如1,3表示第1,2,3行,3,$表示从第三行到最后一行的文本域。美元符号($)表示最后一行。
在地址后加!,代表不在这个范围内。
sed默认行为
1.默认打印
sed默认会输出所有读入模式空间并处理过的文本行(哪怕未被处理过的文本行)。
-
$ sed '/soul/p' plain.txt
-
before my time
-
as my soul heals the shame
-
as my soul heals the shame
-
..
这句打印文件,p会再一次输出带有soul的行;
2. 禁止打印-n和指定输出被处理的行-n,p
因此时常我们要屏蔽这些annoying的输出,用-n选项,屏蔽输出。
经常地,-n和p指令会同时出现,这样可以输出被真正处理过的文本行。
-
$ sed -n '/soul/p' plain.txt
-
as my soul heals the shame
sed修改文件
一般情况下,sed不会修改输入源文件,默认标准输出。若要完成文件修改(生成),可以:
1. shell IO重定向
-
sed '/man/d' < plain.txt > result.txt #把delete后的行写入result.txt
2. 选项-i修改源文件,操作比较危险,谨慎
-
sed -i '/need/NEED/g' result.txt #修改result,执行替换操作
3. 指令w
-
sed -n '1,2w filename' plain.txt #将plain.txt的1,2行写入 filename文件。
sed打印
指令p(结合寻址讲解)
1. 输出文件,同cat
-
$ sed '' plain.txt #利用默认输出行为
-
$ sed -n '1,$p' plain.txt #等价
2. 输出第n行的文本
-
$ sed -n '4p' plain.txt #打印第4行
-
in pouring rain
3. 输出第n到m行的文本,特别的,$代表末行
-
$ sed -n '9,11p' plain.txt #打印第9到11行
-
as my soul heals the shame
-
i will grow through this pain
-
lord i''''m doing all i can
-
----------------------------
-
$ sed -n '1,$p' plain.txt #同cat,全文打印
4. 输出带有soul到带有开头lord的文本行
-
$ sed -n '/soul/,/^lord/p' plain.txt
-
as my soul heals the shame
-
i will grow through this pain
-
lord i''''m doing all i can
-
----------------------------
-
$ sed -n '/doing/,$p' plain.txt #行号、正则两者混用
-
lord i''''m doing all i can
-
to be a better man
sed删除
指令d
1. 删除第n,m行的文本
-
$ sed '1,5d' text.txt #删除1-5行
-
in pouring rain
sed替换
指令s, s/regex_pattern/string_replacement/,分隔符"/"可以是任意其他字符。默认替换第一个,加g参数后sed全局替换(特别的,g换成数字即替换第n个出现的字段)。sed支持BRE+GNU正则,不支持ERE
1. 替换
-
$ sed 's/me/ME/' plain.txt #全文替换并打印
-
send soMEone to love me
-
i need to rest in arms
-
keep ME safe from harm
-
..,
-
-----------------------------
-
$ sed -n '1,$s/me/ME/p' plain.txt #替换的部分打印,此处s,p命令联合,1,$可以忽略。
-
send soMEone to love me
-
keep ME safe from harm
-
give ME endless summer
-
before my tiME
-
as my soul heals the shaME
-
------------------------------
-
sed -n 's/me/ME/gp' plain.txt #加g参数后sed全局替换,默认替换第一个
-
send soMEone to love ME
-
keep ME safe from harm
-
give ME endless sumMEr
-
before my tiME
-
as my soul heals the shaME
-
-----------------------------
-
sed -i 's/me/ME/g' plain.txt #全局替换并修改源文件
-
-----------------------------
-
sed -n 's/me/ME/gpw a.txt' plain.txt #替换后写入文件a.txt
更多sed替换正则例子
此处仅使用正则,将会在另一篇内详细讨论正则表达式。
1. 变换分隔符,当某些情况下需要频繁转义regex和replacement字串时,考虑换一个分隔符;
-
find /home/work -type d | sed 's#/home/work/#/home/rd/#' #将/home/work路径替换为/home/rd,等价于sed 's/\/home\/work\//\/home\/rd\//'
2. 删除字段,用空字符来替换匹配的部分,达到删除的目的;后向引用
-
sed -n 's/\([a-z]\)\1//gp' plain.txt #用到了后向引用,匹配重复2次出现的字母,并删除
-
i nd to rest in arms
-
kp me safe from harm
-
give me endle suer
-
fl i''''m geing old
-
i wi grow through this pain
-
lord i''''m doing a i can
-
to be a beer man
3. 插入字符;
-
sed -n 's/^\(lord\)/Oh \1/gp' plain.txt
-
Oh lord i fear the cold
-
Oh lord i''''m doing all i can
4. 引用匹配的regex,&符号;
-
sed 's/ar/|&|/' plain.txt
-
i need to rest in |ar|ms
-
keep me safe from h|ar|m
5. 使用空的正则;
-
sed -e 's/e/|E|/2' -e 's//{E}/' plain.txt #第二个空正则使用了第一个已经使用了正则/e/,先替换第二个e,在替换第一个e
-
i n{E}|E|d to rest in arms
-
k{E}|E|p me safe from harm
6. 贪婪的正则:正则表达式默认贪婪,总是匹配最长的字串;
-
echo "i need to rest in arms " | sed 's/i.*e//' #匹配了最长的"i need to re"而非"i ne"
-
st in arms
7. 匹配重复字符:\{n,[m]\}
-
sed -n 's/e\{2,\}/X/p' plain.txt
-
i nXd to rest in arms
-
kXp me safe from harm
-
fXl i''''m getting old
8. 扩展正则,单词字符([[:alnum:]_] == \w),单词锚点\b
-
sed -n 's/\b\(\w\)/\U\1/gp' plain.txt #把每个单词的首字符大写
-
Send Someone To Love Me
-
I Need To Rest In Arms
-
...
sed行后追加
指令a\string,当多行时要追加\
1. 默认在每一行后另起追加string内容
-
$ sed 'a\???' plain.txt #每一行后追加
-
send someone to love me
-
???
-
i need to rest in arms
-
???
-
keep m
-
---------------------------------
-
$ sed '3a\yes\
-
or\
-
no' plain.txt #第三行后追加yes\nor\no
-
keep me safe from harm
-
yes
-
or
-
no
2. 在最后一行后加一行作者
-
$ sed '$a\Author : Zzr' plain.txt #追加
-
to be a better man
-
Author : Zzr
指令r filename:将filename文件读入并附加到addr的后一行,等效a\string
-
$ sed '4r standardio.sh' plain.txt
-
keep me safe from harm
-
in pouring rain
-
#!/bin/bash
-
tr -d 'e' < subprocess.sh
sed行前插入
指令i\string
1. 默认在每一行前另起插入string内容
-
sed 'i\string' plain.txt #每一行后追加
-
string
-
send someone to love me
-
string
-
i need to rest in arms
2. 在第一行前加日期
-
$ sed '1i\Date : 20121215' plain.txt #在第一行前加日期
-
Date : 20121215
sed当前行修改
指令c\string
1. 默认修改为每一行的内容为string
-
sed 'c\string' plain.txt #每一行修改为string
-
string
-
string
-
string
2. 在my出现的地方标记为HAVE A MY.
-
sed '/my/c\HAVE A MY' plain.txt #
-
...
-
feel i''''m getting old
-
HAVE MY
-
HAVE MY
-
i will grow through this pain
sed字符映射替换
指令y/char_set1/char_set2/
1. 功能和tr类似,将char_set1里的每个字符依次映射到char_set2的字符集
-
$ sed 'y/aeiou/AEIOU/' plain.txt #a->A,e->E,i->I,o->O,u->U
-
sEnd sOmEOnE tO lOvE mE
-
I nEEd tO rEst In Arms
-
kEEp mE sAfE frOm hArm
-
---------------------------------
-
tr 'aeiou' 'AEIOU' < plain.txt #等价
sed退出
指令q
1. 只要到q,立即退出sed程序
-
$ sed 'Nq' plain.txt #到第N行就退出
-
$ sed -n '1,Np' plain.txt #等效
-
$ head -n N plain.txt #等效
-
----------------------------
-
1 send someone to love me
-
2 i need to rest in arms
-
3 keep me safe from harm
sed多行命令
选项e,编辑命令的顺序会影响结果
-
sed -e '1,5d' -e 's/me/ME/' plain.txt #先删行,再替换
-
-------------------------------
-
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
sed引用shell变量
-
方法1:用""取代'',在sed的命令行中引用shell变量时要使用双引号,而不是通常所用的单引号。
-
$ var=ME
-
$ sed -n "1,5s/me/$var/gp" plain.txt
-
send soMEone to love ME
-
keep ME safe from harm
-
give ME endless sumMEr
-
-----------------------------------------
-
方法2:用'$var'的形式引用
-
$ 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
阅读(1355) | 评论(0) | 转发(0) |