Fung's DBA World

DBA knowledge,standing on the shoulders of giants.

[Shell学习笔记]sed流编辑器

September 26, 2013

1.sed简介

sed也叫流编辑器,它能执行vi相同的编辑任务。但是sed没有破坏性,它不会修改文件,默认情况下,所有的输出行将被列印到屏幕上。 通过shell脚本中调用sed,可以将原文件重定向到新文件中执行编辑任务。同样,sed支持grep中的正则表达式。

1-1     sed使用的正则表达式元字符

元字符 功能 示例 匹配对象
^ 行首定位符 '^love' 匹配所有以love开头的行
$ 行尾定位符 'love$' 匹配所有以love结尾的行
. 匹配单个字符 'l..e' 匹配包含一个l,后面跟两个字符,再跟一个e的行
* 匹配0或者多个重复的位于*前的字符 '*love' 匹配包含跟在0个或者多个字符后的love的行
[] 匹配一组字符中的任意一个 '[Ll]ove' 匹配Love或者love
[^] 匹配不在指定组内的字符 '[^A-Z]' 匹配不在范围A至Z之间的任意一个字符
\< 词首定位符 '\<love' 匹配包含以love开头的词的行
\< 词尾定位符 'love/>' 匹配包含以love结尾的词的行
\(..\) 标记匹配到的字符 '\(love\)ing' 模式love被保存在1号寄存器中,之后可用\1引用它
x\{m\}或x\{m,\}或x\{m,n\} 字符x的重复次数:m次、至少m次、至少m次但不超过n次 'o\{5\}','o\{5,\}','o\{5,10\}' 匹配连续出现5个o、至少5个o或者5~10个o的行
& 保存查找串以便在替换串中引用 's/love/**&**/' 符号&代表查找传。字符串love将替换前后各加了两个*号的引用,即love变成**love**

说明:
1
2
3
4
5
6
[root@linora shell]# grep 'Fung' lettle 
[root@linora shell]# echo $? 
1
[root@linora shell]# sed -n '/Fung/p' lettle 
[root@linora shell]# echo $? 
0
使用grep时,正则表达式Fung没有包含在分隔符中,如果找到模式Fung,grep命令退出状态为0,否则不为0,但是sed不管找到与否,退出状态都为0。这是因为sed只会在发生语法错误的时候,退出状态才不为0。

1.1.定址

定址可以决定对哪些行进行编辑。地址的形式可以是数字或是正则表达式。如果没有指定地址,sed默认处理输入文件中的所有行。

如果指定地址是一个数字,则这个数字代表行号。美元符号表示输入文件的最后一行。如果给出的是逗号分隔的两个行号,那么需要处理的地址就是包括两行之间的范围。

1
2
3
4
5
6
[root@linora shell]# wc -l myfile 
6 myfile 
[root@linora shell]# sed '1,3d' myfile 
The winning ticket is 55222. 
The ticket I got is 54333 and Dee got 55544. 
Guy fell down while running around the south bend in his last event. 
上述sed命令表示删除myfile中1~3行。

1.2.命令与选项

1-2     sed命令

命令 功能
a\ 在当前行添加一行或者多行
c\ 用新文本修改(替换)当前行中的文本
d 删除行
i\ 在当前行之前插入文本
h 把模式空间里的内容复制到暂存缓冲区
H 把模式空间里的内容追加到暂存缓冲区
g 去除暂存缓冲的内容,将其复制到模式空间,覆盖该处原有的内容
G 去除暂存缓冲的内容,将其复制到模式空间,追加在原有内容的后面
l 列出非打印字符
p 打印行
n 读入下一输入行,并从下一条命令而不是第一条命令开始对其的处理
q 退出sed
r 从文件中读取输入行
! 对所选行以外的所有行应用命令
s 用一个字符串替换另一个
替换标志
g 在行内进行全局替换
p 打印行
w 将行写入文件
x 交互暂存缓冲区与模式空间的内容
y 将字符转为另一个字符(不能对正则表达式使用y命令)

1-3     sed选项

选项 功能
-e 运行多项编辑
-f 指定sed脚本文件名
-n 取消默认的输出

1.3.sed范例

1.3.1打印:p命令

默认情况下,sed把输入行打印在屏幕上,但当-n和命令p同时出现时候,sed可打印选定的内容。
1
2
3
4
5
6
7
8
9
10
[root@linora shell]# sed '/55222/p' myfile 
Unusual occurrences happened at the fair. 
Patty won fourth place in the 50 yard dash square and fair. 
Occurrences like this are rare. 
The winning ticket is 55222. 
The winning ticket is 55222. 
The ticket I got is 54333 and Dee got 55544. 
Guy fell down while running around the south bend in his last event. 
[root@linora shell]# sed -n '/55222/p' myfile 
The winning ticket is 55222. 

1.3.2删除:d命令

命令d用于删除输入行。Sed将输入行从文件复制到模式缓冲区,然后对该行执行sed命令。最后将缓冲区的内容显示在屏幕上。
1
2
3
[root@linora shell]# sed '3,$d' myfile 
Unusual occurrences happened at the fair. 
Patty won fourth place in the 50 yard dash square and fair. 
删除第三行到最后一行,美元符号表示最后一行。

1.3.3替换:s命令

替换和取代文件中的文本可通过sed中的s命令来实现。s后包含在斜杠中的文本是正则表达式,后面跟着的是需要替换的文本,可以通过g标志对行进行全局替换。
1
2
3
4
5
6
7
8
9
10
[root@linora shell]# sed -n 's/5/6/' myfile 
The winning ticket is 65222. 
The ticket I got is 64333 and Dee got 55544. 
[root@linora shell]# sed 's/5/6/g' myfile 
Unusual occurrences happened at the fair. 
Patty won fourth place in the 60 yard dash square and fair. 
Occurrences like this are rare. 
The winning ticket is 66222. 
The ticket I got is 64333 and Dee got 66644. 
Guy fell down while running around the south bend in his last event. 
当“&”符号用在替换串中时,它代表在查找串中匹配到的内容,以下sed命令表示找到5个数字后面跟句号结尾的字符串,在此字符串后加上6.结尾:
1
2
3
[root@linora shell]# sed -n 's/[0-9]\{5\}\.$/&6./p' myfile 
The winning ticket is 55222.6. 
The ticket I got is 54333 and Dee got 55544.6. 
以上功能同样可以使用 \(\)替代标签实现:
1
2
3
[root@linora shell]# sed -n 's/\([0-9]\{5\}\)\.$/\1.6\./p' myfile 
The winning ticket is 55222.6. 
The ticket I got is 54333 and Dee got 55544.6. 
说明:
\([0-9]\{5\}\) 
此正则表达式表示将含有5个数字的字符串以标签形式保存在缓冲区中,因为它是第一个标签,所以,被标记为\1。
\.$ 
反斜杠对句号进行转义,$表示结尾,综合起来就是以五个数字加句号结尾的字符串。

1.3.4指定行的范围:逗号

行的范围从文件中的一个地址开始,在另一个地址结束。地址范围可以是行号,正则表达式或者是两者的结合。如果结束条件无法满足,就会一直操作到文件结尾。如果结束条件满足,则继续查找满足开始条件的位置,范围重新开始。

打印从第五行开始到east开头的所有行。

1
[root@linora shell]#  sed -n '5,/^east/s/$/**VA**/p' datafile 
说明: 打印第五行开始到以east开头的行,并且在行尾添加**VA**。

1.3.5多重编辑命令:e命令

如果需要sed执行多个编辑任务,可用-e命令。在下一行开始编辑前,所有的编辑动作都将应用到缓冲区中的行上。即多个命令的结果是有顺序性的。
1
[root@linora shell]# sed -e '1,3d' -e 's/Hemenway/Jones/' datafile 
说明: 上例中,sed首先删除1~3行,然后将剩余行中的Hemingway取代为Jones。

1.3.6读写命令

sed使用r命令将一个文本文件中的内容添加到当前文件的特定位置上。
1
2
3
4
5
6
7
8
9
[root@linora shell]# cat newfile 
Hi,I'm a new file!!! 
[root@linora shell]# cat oldfile 
Hi,I'm a oldfile! 
Next comming up is a newfile! 
[root@linora shell]# sed '/newfile/r newfile' oldfile 
Hi,I'm a oldfile! 
Next comming up is a newfile! 
Hi,I'm a new file!!! 
sed使用w命令将当前文件中的一些行写入到另一个文件中。
1
2
3
4
5
[root@linora shell]# sed -n '/north/w newfile' datafile 
[root@linora shell]# cat newfile 
northwest       NW      Charles Main            3.0     .98     3       34 
northeast       NE      AM Main Jr.             5.1     .94     3       13 
north           NO      Margot Weber            4.5     .89     5        9 

1.3.7其他命令

1
2
[root@linora shell]# sed -n '/eastern/{ n; s/AM/PM/p; }' datafile 
northeast       NE      PM Main Jr.             5.1     .94     3       13 
说明: n命令表示获取下一行,上例中,sed查找eastern模式,然后在下一行中执行s/AM/PM/命令,即替换AM为PM。然后在继续往下处理。
1
2
3
4
5
6
7
[root@linora shell]# sed '1,3y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/' myfile 
UNUSUAL OCCURRENCES HAPPENED AT THE FAIR. 
PATTY WON FOURTH PLACE IN THE 50 YARD DASH SQUARE AND FAIR. 
OCCURRENCES LIKE THIS ARE RARE. 
The winning ticket is 55222. 
The ticket I got is 54333 and Dee got 55544. 
Guy fell down while running around the south bend in his last event. 
说明: y命令表示替换命令,上例中,将1~3行小写字母全部替换成大写字母。
1
[root@linora shell]# sed '10,20s/cow/COW/g' datafile 
说明: 将10~20行替换后的结果输出。
1
[root@linora shell]# sed -n '/The/s/$/!!!/p' myfile 
说明: 在所有含有The的行尾添加!!!。

1.4.sed脚本范例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
[root@linora shell]# cat -n sedding1 
1  # My first sed script 
2  /Lewis/a\ 
3      Lewis is the TOP Salesperson for April!!\ 
4      Lewis is moving to the southern district next month.\ 
5      CONGRATULATIONS! 
6  /Margot/c\ 
7      *******************\ 
8      MARGOT HAS RETIRED\ 
9      ******************** 
10  1i\ 
11  EMPLOYEE DATABASE\ 
12  ------------------------- 
13  $d 
14   /^ *$/d 
说明: 第二行表示如果找到包含模式Lewis,就将3~5行加到它后面。所有追加内容中,除了最后一行外,每一行都以反斜杠结尾。反斜杠后必须紧跟换行符;如果换行符后有多余的文字,哪怕是空格,sed都会报错。所追加的最后一行内容不需要以反斜杠结尾,于是sed知道这是要追加的最后一行,下一行便属于另一条命令了。 第六行查找所有包含模式Margot的行,并且以7~9三行替换(c命令)。 第十行,第一个字符是数字1,表示11~12行被插入到第一行的前面(i命令)。 第十三行,最后一行被删除。 第十四行,删除空行。

1.5.sed总结

表1-4 sed总结

命令 功能
sed –n '10,20p file 打印10~20行
sed '1,10s/AM/PM/g' file 将1~10行所有AM修改为PM
sed '/March/!d' file 删除所有不含March的行
sed '/reports/s/5/8' file 将所有包含reports的行出现的第一个5改为8
sed 's/....//' file 删除每行的前四个字符
sed 's/...$//' file 删除每行的后三个字符
sed '/east/,/west/s/A/B/' file 把从east到west这个范围内所有行中出现的A改为B
sed -n '/Time/w newfile' file 将file中所有包含Time的行写入到newfile中
sed 's/\([Oo]ccur\)ence/\1rence/' file 将所有的Occurrence替换成Occurrence,将所有的occurrence替换成occurrence
练习:

Write a sed script that will
a. Insert above the first line the title PERSONNEL FILE.
b. Replace the line containing Jose with JOSE HAS RETIRED.
c. Change Popeye's birthday to 11/14/46. Assume you don't know Popeye's original birthday. Use a regular expression to search for it.
d. Remove the salaries ending in 500.
e. Append three asterisks to the end of lines starting with Fred.
f. Print the contents of the file with the last names and first names reversed.
g. Append at the end of the file THE END.
ANSWER:
1
2
3
4
5
6
7
8
9
10
11
#My first sed exercise 
1i\ 
PERSONNEL FILE 
/Jose/c\ 
JOSE HAS RETIRED 
/Popey/s/[0-9]\{1,2\}\/[0-9]\{1,2\}\/[0-9]\{1,2\}/11\/14\/46/ 
s/[0-9]*500$// 
/^Fred/s/$/***/ 
s/\([a-zA-Z]*\) \([a-zA-Z]*\)/\2 \1/ 
$a\ 
THE END 

EOF

Permalink: http://www.oraclema.com/linux/sed-study.html