sed是什么:
sed是一个非交互式的流编辑器(stream editor)。所谓非交互式,是指使用sed只能在命令行下输入编辑命令来编辑文本,然后在屏幕上查看输出;而所谓流编辑器,是指sed每次只从文件(或输入)读入一行,然后对该行进行指定的处理,并将结果输出到屏幕(除非取消了屏幕输出又没有显式地使用打印命令),接着读入下一行。整个文件像流水一样被逐行处理然后逐行输出。(via Walk in Mindfields )
sed工作机制:
sed维护两个缓冲区,pattern space和hold space,命令开始执行之前都为空。
pattern space缓冲区用于临时保存每次读取的一行的内容,大部分的匹配和替换等等操作都是针对pattern space中的内容进行的,因此不会对输入文件有任何影响,而hold space则作为后备缓冲区使用,除非指定了一些特殊的命令(例如D删除命令),否则pattern space中的内容会在处理完一行之后清空,但hold space中的内容在处理完每一行时不会被删除。
也就是说pattern space相当于我们的内存,hold space相当于硬盘.处理的时候在内存里,处理过的就放回硬盘.(这是我的理解,有一点点不恰当,但是因此一些概念会比较好理解.)
具体来说,可以大致分为以下几步:
1.首先,从标准输入流读取一行,移除换行符,然后存入pattern space中
2.执行指定的命令,(每个命令都有一个可选的地址(可以是行号,也可能是一个正则表达式匹配),这个地址作为一个执行命令前的测试,指定了需要对那些行进行操作。当前行只有匹配的情况下才会执行命令。)
3.当指定所有的命令都执行完了之后,pattern space内容就被处理过了,sed默认会将pattern space中的内容打印到标准输出中,移除的换行符也会打印出来。本行操作完成。
4.然后sed会读取下一行的内容,再次执行相同的操作。直到行尾。
形式上,使用sed采用如下命令格式:
sed [options] 'SELECTION edit-instructions' file(s)
常用options:
-n :使用安静(silent)模式。在一般sed的用法中,所有来自STDIN的数据一般都会被列出到终端上。但如果加上-n参数后,则只有经过sed特殊处理的那一行(或者动作)才会被列出来。
-e :直接在命令列模式上进行sed的动作编辑;
-f :直接将sed的动作写在一个文件内,-f filename 则可以运行filename内的sed动作;
-r :sed 的动作支持的是延伸型正规表示法的语法。(默认是基础正规表示法语法)
-i :直接修改读取的文件内容,而不是输出到终端。
1)范围选取
SELECTION 可以如下表达:
- 单个行号:如1为取第一行,5为取第五行,$为取最后一行
- 行范围:如5,$ 为取从第五行到最后一行之间的文本行
- 单个正则匹配:如/string/ 为取包含string的行
- 一个正则匹配范围:如/^on/,/off$/ 为取从on开头的行到off结尾的行之间(含这两个匹配行)所包含的文本行。
- 行范围与正则匹配范围集合:如10,/man/表示从第10行到包含有man的行之间的文本
- 除去所匹配行外的范围:如/Llew/! 表示除了匹配Llew的行外其余的文本行
2)打印命令
基本语法:SELSECTIONp 打印pattern space中的内容
Task1:打印包含Franklin的行
sed -n '/Franklin/p' phonelist
注意,选项-n 表示所有都不打印,而仅仅打印出匹配的行,可以试一试没有这个选项的情况。回顾sed机制,它会将文本一行行放在pattern space,不管你做什么样的后续操作、甚至不做任何编辑动作,它都会在command执行完后把pattern space打出来,这你就理解了为什么要用这个选项。
3)处理命令
a) 增改操作:
基本语法:
SELECTIONx\
text
其中斜杠后有回车,而x则为:
i 表示插入选中行前
a 表示追加在选中行之后
c 表示将选中行修改为text
Task2:在第二行前插入一个联系人Jonney, Wang 923-3322
sed '2i\
Jonney, Wang 923-3322' phonelist
Task3:在Martin, Marty所在行之后加入联系人Jonney, Wang 923-3322
sed '/Martin, Marty/a\
Jonney, Wang 923-3322' phonelist
Task4:将名字为Llewellyn的行记录都记为“BANNED”
sed '/Llewellyn/c\
BANNED' phonelist
b)删除操作
基本语法:
SELECTIONd ,清除pattern space中的所有内容
Task5 删除最后一行:
sed '$d' phonelist
c)替换操作:
基本语法:
'SELECTION s/old string/new string/’ 替换所选区域中第一次出现的old string
'SELECTION s/old string/new string/g’ 替换所选区域中所有的old string
'SELECTION y/string1/string2/’ 对所选区域中的string1所含字符对应替换为string2中同位置的字符,与tr命令相同。
Task6:将第一个Robin替换为Robbins
sed 's/Robin/Robbins/' phonelist
Task7:将所有Rob替换为John
sed 's/Rob/John/g' phonelist
Task8:将/usr/bin/中的/bin/替换为/bin
sed 's/\/bin\//\/bin/' paths
在这种出现很多/的文件时需要\来进行转义,稍微一多就容易出错,那么采用如下的方式把替换分隔符的方式进行就好,其中感叹号只是一个其他类字符,换做另外一个字符(例如@)也是没有关系的:
sed 's!/bin/!/bin!' paths
Task9:加密所有的1234,规则为将文件中1、2、3、4对应改为A、B、C、D:
sed 'y/1234/ABCD/' phonelist
d)写文件操作:
基本语法:'SELECTION command/w filename’
Task9:将所有Rob 改为Robbin,并将结果写到一个叫做result 的文件中
sed 's/Rob/Robbin/gw result' phonelist
e)读文件操作:
基本语法:'SELECTION command/r filename’
Task10:如果phonelist中存在Patterson,则将文件paths的内容加入到Patterson后的那一行
sed '/Patterson/r paths' phonelist
f)批处理操作:
如果要处理的很多,我们也可以将sed命令写入一个脚本,然后运行时采用-f选项指定运行该脚本就行。请注意sed会将第一条命令执行的结果发给第二条执行,因此命令的顺序尤为重要。
基本语法:sed -f scriptfile filename
另一种方式是使用-e选项,基本语法为:
-e ‘command1’ –e ‘command2’
Task11:将Martin替换Mary,将Tearrey替换为Tearrey
sed -e 's/Martin/Mary/' -e 's/Terrell/Tearrey/' phonelist
另外一种方法,有点类似于C语言中分号的使用:
sed 's/Martin/Mary/;s/Terrell/Tearrey/' phonelist