sed学习笔记(不断更新补充)

来源:互联网 发布:八上政治行知天下答案 编辑:程序博客网 时间:2024/05/16 04:23
在字符串处理中,sed非常强大,从前就了解皮毛,而在笔者某次网络电面中就曾遇到,只能现查man文档解决问题,非常窘迫。现进行系统学习,笔记于此。

参考
sed新手使用进阶全功略!
http://www.linuxsir.org/bbs/showthread.php?t=189620

在学习前,首先要保证知道正则表达式的基本知识,此可参见我的另一学习笔记
http://blog.sina.com.cn/s/blog_4d1bbec70100qmxg.html

当然,学习sed的最好办法,是man sed后,阅读其文档。当然,比较舒服的办法还是跟随大牛,理论和实际相结合,学习过程如下。

sed主要用来查找替换,对字符串进行处理,功能强大,其基本格式如下:
sed [-n][-e] 'command' file(s) sed [-n] -f scriptfile file(s)
不用去理会以上格式如何使用,因为我自己在学习时,将其说明阅读若干边依然一头雾水。我是在诸多实例中,明白了其参数和格式的用法和含义。

sed从一个文件的一个文本行或从标准输入的几种格式中读取数据,将之拷贝到一个编辑缓冲区,然后读命令行或脚本的第一条命令,并使用这些命令查找模式或定位行号编辑它。重复此过程直到命令结束。但sed不和输入的文件打交道,它操作的只是文件的一个拷贝(除非用-i和输出重定向改动原文件),然后所有的改动如果没有重定向到一个文件,将输出到屏幕。

sed选项(其具体用法将会示例中展开):
-n 不打印编辑行到标准输出(sed缺省为打印所有行,包括原始行和编译行);
p命令可用来打印编辑行;
-e 允许同一行中执行多条命令
-f 
-c 编译命令
-i 编译原文件
-d 删除命令

sed基础用法
sed在文本中查询时,可用两种定位文本的方式:使用行号;使用正则表达式。方法如下:
x                    此处x为一行号,如1
x,y                 表示行号范围从x到y,如2,5表示从第2行到第5行
/pattern/       查询包含模式的行。例如/disk/或/[a-z]/
/pattern/pattern/   查询包含两个模式的行。例如/disk/disks/
/pattern/,x   在给定行号上查询包含模式的行。如/ribbon/,3
x,/pattern/    通过行号和模式查询匹配行。3,/vdu/
x,y!                查询不包含指定行号x和y的行。1,2!

基本sed编辑命令:
sed编辑命令
p 打印匹配行
= 显示文件行号
a\ 在定位行号后附加新文本信息
i\ 在定位行号后插入新文本信息
d 删除定位行
c\ 用新文本替换定位文本
s 使用替换模式替换相应模式
r 从另一个文件中读文本
w 写文本到一个文件
q 第一个模式匹配完成后推出或立即推出
l 显示与八进制A S C I I代码等价的控制字符
{ } 在定位行执行的命令组
n 从另一个文件中读文本下一行,并附加在下一行
g 将模式2粘贴到/pattern n/
y 传送字符
n 延续到下一输入行;允许跨行的模式匹配语句

示例:有文件test.txt
cat test.txt 
1 The honeysuckle band played all night long for only $90.
2 It was an evening of splendid music and company.
3 Too bad the disco floor fell through at 23:00.
4 The local nurse Miss P.Neave was in attendance.

命令:
$ sed -e '1p' test.txt
1 The honeysuckle band played all night long for only $90.
1 The honeysuckle band played all night long for only $90.
2 It was an evening of splendid music and company.
3 Too bad the disco floor fell through at 23:00.
4 The local nurse Miss P.Neave was in attendance.

$ sed -n -e '1p' test.txt
1 The honeysuckle band played all night long for only $90.

从上面的例子中可以看出,命令-e在此处可有可无,而-n则限制是否将未编辑的初始行打印,1为第一行,p则是指出需要将匹配的行打印出。同样,
$ sed -n -e '2p' test.txt
2 It was an evening of splendid music and company.

打印第二和第三行
$ sed -n -e '2,3p' test.txt
2 It was an evening of splendid music and company.
3 Too bad the disco floor fell through at 23:00.

打印含有company的匹配行
$ sed -n -e '/company/p' test.txt
2 It was an evening of splendid music and company.

打印第2行和含有23:00的匹配行(注意,是分别打印,并不是逻辑与的关系)
$ sed -n -e '2,/23:00/p' test.txt
2 It was an evening of splendid music and company.
3 Too bad the disco floor fell through at 23:00.

打印非第2和第3行(注意其间的逻辑关系)
$ sed -n -e '2,3!p' test.txt
1 The honeysuckle band played all night long for only $90.
4 The local nurse Miss P.Neave was in attendance.

用=打印行号,此处再次注意-n的重要作用
$ sed -e '=' test.txt
1
1 The honeysuckle band played all night long for only $90.
2
2 It was an evening of splendid music and company.
3
3 Too bad the disco floor fell through at 23:00.
4
4 The local nurse Miss P.Neave was in attendance.
和(-n需要放在-e前)
$ sed -n -e '=' test.txt
1
2
3
4

下面还有一些例子:
这个不解释
$ sed -n -e '/music/p' test.txt
2 It was an evening of splendid music and company.
yyang@Yanux:~/shell$ sed -n -e '/music/=' test.txt
2
此处要执行多个匹配,-e的作用亦在此,倘若不加-e,则会报错,只能执行第一个匹配。
$ sed -n -e '/music/p' -e '/music/=' test.txt
2 It was an evening of splendid music and company.
2
还有,
$ sed -e '=;p' test.txt 
1
1 The honeysuckle band played all night long for only $90.
1 The honeysuckle band played all night long for only $90.
2
2 It was an evening of splendid music and company.
2 It was an evening of splendid music and company.
3
3 Too bad the disco floor fell through at 23:00.
3 Too bad the disco floor fell through at 23:00.
4
4 The local nurse Miss P.Neave was in attendance.
4 The local nurse Miss P.Neave was in attendance.
yyang@Yanux:~/shell$ sed -e 'p' test.txt 
1 The honeysuckle band played all night long for only $90.
1 The honeysuckle band played all night long for only $90.
2 It was an evening of splendid music and company.
2 It was an evening of splendid music and company.
3 Too bad the disco floor fell through at 23:00.
3 Too bad the disco floor fell through at 23:00.
4 The local nurse Miss P.Neave was in attendance.
4 The local nurse Miss P.Neave was in attendance.
yyang@Yanux:~/shell$ sed -n -e '=;p' test.txt 
1
1 The honeysuckle band played all night long for only $90.
2
2 It was an evening of splendid music and company.
3
3 Too bad the disco floor fell through at 23:00.
4
4 The local nurse Miss P.Neave was in attendance.
通过上面的三个例子,可以看出;用来分隔两个匹配模式。另外,
$ sed -n -e '=' -e 'p' test.txt
1
1 The honeysuckle band played all night long for only $90.
2
2 It was an evening of splendid music and company.
3
3 Too bad the disco floor fell through at 23:00.
4
4 The local nurse Miss P.Neave was in attendance.
这个例子也说明了上述问题。

a为附加命令,将附加内容附加至匹配行后
$ sed -e 'a\this line will be added to the end of each line!' test.txt
1 The honeysuckle band played all night long for only $90.
this line will be added to the end of each line!
2 It was an evening of splendid music and company.
this line will be added to the end of each line!
3 Too bad the disco floor fell through at 23:00.
this line will be added to the end of each line!
4 The local nurse Miss P.Neave was in attendance.
this line will be added to the end of each line!
$ sed -e '/music/a\this line will be added to the end of each line!' test.txt
1 The honeysuckle band played all night long for only $90.
2 It was an evening of splendid music and company.
this line will be added to the end of each line!
3 Too bad the disco floor fell through at 23:00.
4 The local nurse Miss P.Neave was in attendance.

i为插入命令,将需要插入的内容插入至匹配行前
$ sed -e 'i\this line will be inserted to the begin of each line!' test.txt
this line will be inserted to the begin of each line!
1 The honeysuckle band played all night long for only $90.
this line will be inserted to the begin of each line!
2 It was an evening of splendid music and company.
this line will be inserted to the begin of each line!
3 Too bad the disco floor fell through at 23:00.
this line will be inserted to the begin of each line!
4 The local nurse Miss P.Neave was in attendance.
$ sed -e '/music/i\this line will be inserted to the begin of each line!' test.txt
1 The honeysuckle band played all night long for only $90.
this line will be inserted to the begin of each line!
2 It was an evening of splendid music and company.
3 Too bad the disco floor fell through at 23:00.
4 The local nurse Miss P.Neave was in attendance.

c为行更改命令,而d为行删除命令
$ sed -e '/music/c\this line will  be modified to the matching line!' test.txt
1 The honeysuckle band played all night long for only $90.
this line will  be modified to the matching line!
3 Too bad the disco floor fell through at 23:00.
4 The local nurse Miss P.Neave was in attendance.
$ sed -e '/music/,3d' test.txt 
1 The honeysuckle band played all night long for only $90.
4 The local nurse Miss P.Neave was in attendance.

sed替换
替换命令为s
$ sed -e 's/h/ooooo/' test.txt 
1 Toooooe honeysuckle band played all night long for only $90.
2 It was an evening of splendid music and company.
3 Too bad toooooe disco floor fell through at 23:00.
4 Toooooe local nurse Miss P.Neave was in attendance.
上面的例子中,只用ooooo替换了每行的第一个h;而使用参数g,则可以进行全局替换
$ sed -e 's/h/ooooo/g' test.txt 
1 Toooooe ooooooneysuckle band played all nigooooot long for only $90.
2 It was an evening of splendid music and company.
3 Too bad toooooe disco floor fell tooooorougooooo at 23:00.
4 Toooooe local nurse Miss P.Neave was in attendance.
下面的例子需要理解
$ sed -e '1,2s/h/ooooo/g' test.txt
1 Toooooe ooooooneysuckle band played all nigooooot long for only $90.
2 It was an evening of splendid music and company.
3 Too bad the disco floor fell through at 23:00.
4 The local nurse Miss P.Neave was in attendance.
yyang@Yanux:~/shell$ sed -e '1,2s/h/ooooo/' test.txt
1 Toooooe honeysuckle band played all night long for only $90.
2 It was an evening of splendid music and company.
3 Too bad the disco floor fell through at 23:00.
4 The local nurse Miss P.Neave was in attendance.
在下面的例子中,\$为转义符转义$,命令为只为含有$的行进行全局替换
sed -e '/\$/s/h/ooooo/g' test.txt
1 Toooooe ooooooneysuckle band played all nigooooot long for only $90.
2 It was an evening of splendid music and company.
3 Too bad the disco floor fell through at 23:00.
4 The local nurse Miss P.Neave was in attendance.
而下面的命令中,含有It和23:00的行都将进行替换
$ sed -e '/It/,/23:00/s/l/ooooo/g' test.txt
1 The honeysuckle band played all night long for only $90.
2 It was an evening of spoooooendid music and company.
3 Too bad the disco fooooooor feoooooooooo through at 23:00.
4 The local nurse Miss P.Neave was in attendance.

替换修改字符串&
yyang@Yanux:~/shell$ sed -e 's/$90/&230/g' test.txt 
1 The honeysuckle band played all night long for only $90230.
2 It was an evening of splendid music and company.
3 Too bad the disco floor fell through at 23:00.
4 The local nurse Miss P.Neave was in attendance.
$ sed -e 's/90/120,&/g' test.txt 
1 The honeysuckle band played all night long for only $120,90.
2 It was an evening of splendid music and company.
3 Too bad the disco floor fell through at 23:00.
4 The local nurse Miss P.Neave was in attendance.
不用解释,明白人一看就懂。

sed的基本应用就这样,但更好的掌握则需要不断地使用,在实际应用中扩展对它的了解,熟练应用。今后所得,将会补充于此。
补:
1、语法间的分隔符,不仅仅可以使用/,其他也行。比如下面例子:
$ echo $PWD | sed -e 's/\//@/g'
@home@yyang@shell
我将输出的/转换为@,如果采用上面的方法,各种表达方式错综复杂,不方便阅读。因此可以
yyang@Yanux:~/shell$ echo $PWD | sed -e 's:/:@:g'
@home@yyang@shell
yyang@Yanux:~/shell$ echo $PWD | sed -e 's;/;@;g'
@home@yyang@shell
结论:可以采用其他易于辨认的符号作为语法成分间的分隔符

2、引号的问题
此处对引号的讨论,源于参考中的一个例子,关于更加详细的引号用法,可以参见
说说sed中引号的用法(抛砖引玉!)http://www.chinaunix.net/jh/24/129474.html
参考中的例子如下:
要用sed把字符“\”转化成“'”该怎么写?比如:
$ echo "hello\hh\haha"
hello\hh\haha
按照常理,我们都会如此来书写,但无法得到预期结果
$ echo "hello\hh\haha" | sed -e 's:\:':g' 
> ^C
估计原因出在单引号的匹配上,由于在sed的匹配式中出现了三个单引号',于是系统认为命令还未完结,因此在第二行出现了>,等待继续输入。参考中的正确答案如下,同事也得到了正确的结果。
$ echo "hello\hh\haha" | sed -e 's/\\/'"'"'/g'
hello'hh'haha
经思考,认为s/\\/后的第一个单引号'是用来匹配s前的第一个单引号,而最后的'则是用来匹配g后的单引号,中间的成对双引号" "将一个单引号'引出,表示用于替换的',为了验证想法是否正确,实验如下(双引号中的'被;号替换):
$ echo "hello\hh\haha" | sed -e 's/\\/'";"'/g'
hello;hh;haha
实验成功。

3、分域的问题
4、创建sed脚本的问题