带书签PDF版,喜欢的话,欢迎多提意见和建议,你的支持是血蝙蝠最大的前进动力!
http://download.csdn.net/detail/challenge_c_plusplus/6480007
Part0 Sed预备知识
0.1 什么是Sed
Sed即StreamEDitor中3个大写字母的组合,是一种“流编辑器”。所谓流编辑器,就是面向流的编辑器。所谓流就是应用程序的输入经过程序处理,然后输出到标准输出。通俗点说,sed就是一种通过输入流,比如文件、键盘的输入,然后处理,最终输出到标准输出(即屏幕)的一种文本编辑器。它是unix-like系统下的一个常用文本处理命令。
0.2 Sed相关的正则表达式
读者请注意,通常我们把grep和sed视为一组,因为它们都使用shell的基础正则表达式,我们把egrep和awk视为一组,它们可以使用扩展的正则表达式。这里我们只介绍sed相关的正则表达式,即shell基础正则表达式语法。先说明,不要担心学不会,因为非常简单!
. 代表除去换行符以外的任意单个字符
例1:c.t 可以代表cat,cut,c!t等等
* 不同于通配符,代表重复*前边一个字符任意次,即0次或多次
例2:hello_*world!代表helloworld!,或者hello_world!,或者hello__world!等等
[…] 代表它内部包括的字符的任意一个
例3:a[1234]c代表a1c,或者a2c,或a3c,或a4c
^ 放在正则表达式的开始处,代表一行的开始位置,放在[]中的开始处,代表不是[]中字符的任意字符
例4:^a[^1234]c代表文本中某一行以axc三个字符开头,其中x为不是1234的任意字符
$ 放在正则表达式的结尾处,代表一行的结束
例5:abc$ 代表文本中以abc结尾的文本行
{n,m} 代表重复前边一个字符n到m次中的任何一种。变种有{n}重复前边一个字符n次,{n,}重复前边一个字符至少n次。
例5:abc{2,3}代表abcc或者abccc
< 代表一个单词的开始
例6:<Hello代表包含以Hello开头的单词的行
> 代表一个单词的结束
例7:Hello>代表包含以Hello结尾的单词的行
& 代表匹配内容
例8:s/hello/[&]/g,会将文本中的hello都替换为[hello],其中&代表匹配的hello
n是1-512的任意数字,代表前边第n个符合(…)的匹配
例9:s/([1-9]*)abc([A-Z]*)/21/g表达式,会将123abcABC转换为ABC123,其中1代表([1-9*]], 2代表([A-Z]*)
PartI Sed基本原则
1.1 Sed命令的作用规则
1. 脚本文件中的所有命令会顺序作用于待处理文本中的每一行;
2. 地址过滤作用可以使脚本中的命令只作用于与地址匹配的特定行;
3. 原始文本文件不会被改变,被改变的是原始文件的一个备份,处理后的备份行会输出。
1.2 模式空间(The Pattern Space or The Temporary Buffer)
存放sed脚本命令处理的当前行,即当前处理行的备份,命令实际改变的是这份备份,最后输出的也是这份备份。
1.3 Sed命令地址详解
(四种地址情况) 其中,地址可以是“正则表达式、行号、行中部分文本信息”三种
1. 无地址 脚本中命令作用于所有行,例如 d 删除所有行
2. 一个地址 命令作用于与地址匹配的对应行,例如 1d删除第一行,2d删除第二行
3. 逗号分隔的两个地址 命令作用于两个地址之间的所有行,例如1,/^$/d删除第一行到第一个空行之间的所有行
4. 地址后直接跟!号,命令作用于所有与地址不匹配的行 例如1!d删除除第一行外的所有行
1.4 大括号的使用
作用:嵌套地址,组合命令。左大括号必须在一行的末尾,右大括号必须独立成行,大括号后边直接跟回车,不能有空格。
例1:删除1-5行中的空白行
1,5{
/^$/d
}
例2:从1-5行中删除含linux或unix的行
1,5{
/linux/d
/unix/d
}
1.5 Sed应用场景
1 同时编辑多个同类文件
2 修改文件内容
3 提取文件内容
1.6 Sed命令的两种使用方式
方式一:使用脚本文件,语法:sed [other options] –f script.sed file
方式二:直接使用命令行,语法 sed [options] ‘command’ file
Sed命令使用时,可以直接在命令行使用,将命令通过单引号括起来,也可以将命令按行写在一个文本文件中,然后使用Sed的-f选项来加载脚本文件中的Sed命令集合。
1.6.1 命令行方式
最简答的命令行方式,比如sed‘1d’ file,表示删除文本文件file中的第一行;
复杂点的就是包含多个命令的情况,有三种解决方式:第一种,在一个单引号里使用分号分隔各个命令,比如sed ‘1d;5d;9d’ file,就是删除第1,5,9行文本;第二种,使用多个-e选项分隔各个命令,比如sed –e ‘1d’ –e ‘5d’ –e ‘9d’ file;第三种,使用换行符来分隔各个命令,比如,其中#代表shell的命令提示符,>代表键入回车后的提示符:
# sed ‘1d <键入回车>
> 2d <键入回车>
> 3d’ file
更为复杂点的是,命令中含有用于过滤文本行的地址信息,同时要求执行多个命令,这时候要使用大括号{}。比如
# sed ‘5,/^$/{ <键入回车>
> /hello/d <键入回车>
>s/word/words/g <键入回车>
> }’ file
其中,5,/^$/ 代表仅针对第5行到后边第一个空白行间的文本行,/hello/代表含有hello的文本行,s命令代表将word全部替换为words,g标记代表处理对应行中所有出现的word,没有g代表仅处理对应行中第一个word。
注意:有些情况使用大括号可以不用键入回车,但是键入回车肯定可以保证不出问题,所以建议始终在使用大括号时键入回车!
1.6.2 脚本文件方式
了解了上边的命令行方式,就好了解脚本方式了。脚本方式就是将多条命令放置到一个文本文件中,其格式如下:
/address/{
Cmd1;
Cmd2;
…
Cmdn;
}
这种形式其实和sed命令行使用大括号是一样的,只是由于命令多了,写在文件了比较方便,而且便于重用。其中,内部的cmd可以是以上形式的嵌套,就是大括号里面还可以再有地址,然后在使用大括号,到括号里面又是命令。
将以上内容存于文件中,然后使用以下命令,即可执行:
sed –f script.file file
PartII 初级Sed命令
2.1 基本Sed命令语法
Sed命令语法:[address]command
Sed语法:sed [options] [actions]file
1. Sed –f sed.script file
2. Sed ‘actions’ file
3. Sed在命令行使用多条命令的三种方式:
使用多个-e选项,每个后边接一条命令;
使用分号分隔多条命令;
在写闭合的单引号之前使用回车,每条命令后边加回车
Sed使用#作为注释符号,#号后边紧跟n,相当于使用-n参数,不默认输出文本内容
2.2 Sed主要选项
-n 抑制命令自动输出patternspace中的内容,默认情况下,pattern space中的内容,如果执行完所有处理命令,结果会被输出,使用该选项使得patternspace中的内容不会自动输出,通常该选项和p命令一起使用,以便输出当前处理行,单独使用p命令,同一行会被输出两次。
-f 用于使用sed脚本的情况,后接脚本文件名
-e 后接单引号括起来的命令串,使用多个命令,可以通过多次使用-e选项实现
-i 直接修改原文件内容,默认不输出到屏幕
-r 在命令中使用扩展的正则表达式,扩展正则表达式,我们会在<<掌握awk命令>>中提到,强大的选项!!!(该选项不在本文讨论范文内)
2.3 12种基本命令
Subsititution:即s命令,文本替换命令(常用)
语法:[address]s/pattern/replacement/flag
Address代表要处理的行,可以是行号,正则表达式,特定行中的部分文本片段
Pattern代表模式字符串
Replacement代表用来替换模式字符串的字符串
Flag有n,g,p,w file四种,n代表(1-512)中一个数字,表示替换操作作用于当前行中出现的第几个pattern串;g代表替换操作处理当前行中出现的所有pattern串,p代表打印当前行,该标志通常与-n选项连用,表示只打印处理过的行;w file表示将处理行写入文件file中。
注意:分隔用的/可以使用其他合法符号,比如!,:等,最后,不使用任何标志表示仅作用于第一个匹配
Replacement中可用的三种特殊符号:& 代表pattern匹配的字符串, 代表由第几个(pattern)匹配的串,代表转义字符,在Replacement中只有这三个特殊符号,其他都不是特殊符号,不需要转义
Delete,即命令d,删除命令,语法:[address]d(常用)
删除匹配形式的行,注意是删除整行,而不是仅删除行中匹配的模式字符串
Append,Insert,Change,即命令a,i,c,追加、插入、更改命令,语法[address](a|i|c) eplacement
Append在指定行后插入,insert在指定行前插入,change用replacement替换指定行
List命令,即l命令,列出指定行中的不可打印字符,如tab键,换行符等
Transform命令,即命令y,转换命令,最特殊的一个命令,所有其他命令都是对应单词的首字母,只有这个命令不是对应单词首字母,因为test(t)命令已经存在了。
语法:y/abc/ABC/ 该命令用于对应字符转换,类似于tr,但没有tr命令应用范围广,abc与ABC必须字符个数相等,对应转换,而不能使用[0-9]这种形式,即a转换为A,b转换为B,c转换为C。
Print命令,即p命令,打印匹配行,通常与选项-n一起使用,不使用-n同一行会被打印两次。特殊符号=,与p命令联合使用,可以输出行号,行号独立成行,=等号必须是地址后边第一个出现,在p命令之前(常用)
例子:输出第一行到第一个空行中的所有行,并输出行号
1,/^$/{
=
p
}
Next命令,即n命令。输出当前行,并将下一行输入到模式空间中。(常用)
注意:出现在n命令之前的命令不会作用于新输入的行,出现在n命令之后的命令也不会作用于n命令输出去的行
Read与Write命令,即r和w命令,如法[address](r|w)file
r,将文件读入到当前行之后
w,将当前行写入到文件
Quit命令,即q命令,遇到地址行就退出sed,其中匹配的地址行也要输出
其中,s,d,p,n是最常用的几个命令,y是最特殊的一个命令,因为其它所有命令都是以单词首字母命名,它不是。
PartIII 高级Sed命令
3.1多行模式空间与备份空间
多行模式空间(MultilinePattern Space):就是在模式空间中放置输入文件的多个行内容。
备份空间(The Hold Space):用于备份Pattern Space中的内容的空间。
3.210种高级Sed命令
三组高级sed命令:
1操作多行模式空间的命令(N,D,P)
2处理模式空间与备份空间内容交换的命令(H,h,G,g,x)
3 sed脚本控制流命令(b,t)
N,D,P命令分别为n,d,p命令的大写形式,其含义类似,略有不同:
N命令,与n不同,它不输出模式空间中的当前行,而是将下一行也输入到模式空间中,当前行与下一行之间插入一个’ ’,以下为示意图:
图1. 调用N命令后的Multiline Space
注意:调用N后只有最初和最后有^$标记, 前后并没有这些标记
D命令不同于d命令,d命令删除Pattern Space中的内容,而D命令仅删除Multiline Space中第一个’ ’之前的内容,如图1 中,即删除“The Unix Operating System”,而“Is A interesting System”仍然存在。同时,它使得脚本的控制流转到脚本文件的第一行,跳过该命令的后续命令。
P命令不同于p命令,p命令打印Pattern Space中的内容,而P命令仅打印Multiline Space中第一个’ ’之前的内容,如图1中,即仅打印“The Unix Operating System”.
H和h命令,hold之意,将Pattern Space中的内容备份到Hold Space中,大写命令是追加到Hold Space中,小写命令是覆盖HoldSpace中的内容;
G和g命令,get之意,即将Hold Space中的内容取到Pattern Space中,大写代表追加,小写代表覆盖。
x命令,交换Pattern Space和Hold Space中的内容。
b命令(branch)和t命令(test)用于控制sed脚本流程。
b命令语法:[address]b[label]
例子:
:Hello
Command
Command
/address/b Hello
Command
b命令使得脚本控制流转到:Hello的下一行,如果没有使用标签,则直接跳转到脚本结尾。
t命令语法:[address]t [label]
例子:
s/ //
t
command
t命令含义是,如果上边的替换命令s成功,则跳转到标签处,如果没有标签,跳转到脚本结尾,如果不成功则继续执行后续命令。
总结,掌握Sed,掌握Shell的基本正则表达式,12中基本Sed命令+10中高级Sed命令,Sed命令除y命令(transform)外,其它命令都是英文单词首字母,很好记忆。当然,这里不是Sed的全部命令,其它一些命令不太常用,就不再介绍。最后一部分,我们以一些常见的sed命令处理案例,来加深理解上边的理论介绍部分,以便彻底掌握这个实用工具。
PartIV 实践练习
[d删除命令]
$ sed ‘2d’ file #删除file中的第2行
$ sed ‘2,$d’ file #删除第2行到最后一行的所有行
$ sed ‘/hello/’ file #删除包含hello的行
$ sed ‘1d;5d;10d’ file #删除第1,5,10行
$ sed ‘/^$/d’ file #删除file中的空行
$ sed ‘5,10!d’ file #删除5-10以外的所有行
总结:d命令有三种地址模式,行号,行中字符串片段,正则表达式,对于后两种需要使用//包围地址,如/hello/和/^$/,还有一点,两个地址间的逗号,表示作用范围为两个地址之间,!代表取补集
[s 替换命令]
$ sed ‘s/test/Test/’ file #用Test替换每行中第一个test
$ sed ‘s/test/Test/5’ file #用Test替换每行中第5个出现的test
$ sed ‘s/test/Test/g’ file #用Test替换每行中所有test
$ sed –n‘s/^test/Test/p’ file #-n与p合用,仅显示发生替换操作的行,
#Test替换以test开头的行的开头的test
$ sed ‘s/^192.168.0.1/&localhost’ file # &表示匹配到的内容,用
#192.168.0.1localhost替换以192.168.0.1
#开头的行的开头的192.168.0.1
$ sed –n‘s/(love)able/1rs/p’ file #1代表(love)匹配到的内容,用lovers
#替换包含love的行中第一个出现的love
$ sed ‘s#10#100#g’ file #用100代替每行出现的10,这里#等于/
$ sed –n‘/test/,/check/p’ file #仅打印第一包含test的行到第一个包含
#check的行之间的所有行
$ sed –n‘5,/^test/p’ file #打印第5行到第一个以test开头的行
#之间的所有行
$ sed ‘/test/,/check/s/$/HelloEnd’ #在第一个包含到第一个包含check的行
#后边追加HelloEnd
$ sed –e‘1,5d’–e‘s/test/check/’ file #删除1-5行的内容,将文件中每行第一个
#test替换为check,前边命令影响后边命令
总结:命令中体现了p命令的使用,通常与-n选项连用,s命令是最常用的,注意分隔符可以用其他符号代替,注意逗号可以表示地址区间,以及//包围地址的使用
[n下一行命令]
$ sed ‘/test/{n;s/aa/bb/}’ file #读到含test的行,输出该行,然后
#读入下一行,用bb替换下一行出现
#的第一个aa,循环执行以上动作
该命令可以写为以下方式
$ sed ‘/test/{ <键入换行符>
>n <键入换行符>
>s/aa/bb <键入换行符>
>}’ file
总结:n命令前边的命令不会作用于下一行,n命令后边的命令不会作用于当前行
[r 文件读入命令]
$ sed ‘/test/rfile2’ file1 #将file2的内容插入到file1中含有test的每一行之后
[w 文件写入命令]
$ sed ‘/test/wfile2’ file1 #将file1中每个含有文本test的行追加到file2中
[a 追加命令]
$ sed ‘/test/a hisis append line’ file #在含有文本test的行后边插入一行内容为
#thisis append line的文本
[i 插入命令]
$ sed ‘/test/i hisis a insert line’ file #类似如a命令,在对应行前边插入
[c 替换命令]
$ sed ‘3,5c hisis a change line’file #将文件file的第3-5行内容替换为一行,
#其内容为this is a change line
[y 转换命令]
$ sed ‘1,10y/abcd/ABCD/’ file #将file前10行中所有的字符a,b,c,d转换为大写
[q 退出命令]
$ sed ‘10q’ file #处理完(默认为打印)第10行,sed命令结束
#q命令与b,t等命令可以用于流程控制
[N 下一行追加命令]
问题描述:用sed实现去换行的功能,即tr –d‘ ’的功能
sed –fscript.file file #其中script.file为sed脚本文件,名字可以随便取
#file为待处理文件
Script.file脚本文件内容如下:
{
N #将下一行追加到模式空间,现在空间中有两行内容,中间用 分隔
s/ // #删除 ,执行完这里sed对下一行继续处理
}
当然,左大括号{左边可以通过加地址信息限制处理哪几行,这个功能当然可以不写脚本文件,直接在命令行执行,如下:
sed ‘N;s/ //’ file
再强调一次,脚本文件都可以写成命令行方式,放过来也成立,就是看你觉得怎么方便而已!
[N P D 循环] #联合使用N-P-D,操作控制流
问题描述:如下文本文件,如果UNIX System出现以下情况:UNIX是一行的最后一个单词,System是下一行的第一个单词,则将UNIX System替换为UNIX Operating System,新的换行符在System之后。
file内容如下:
Here are examples of the UNIX
System. Where UNIX
System appears, it should be the UNIX
Operating System.
处理后输出结果为:
Here are examples of the UNIX Operating System.
Where UNIX Operating System appears, it should be theUNIX
Operating System.
实现脚本如下:
/UNIX$/{
N #在UNIX结尾的行后追加下一行,中间有 分隔
s/ (System.*)/ Operating 1 / #替换,这里的特殊用法稍后讲述
P #输出 之前的内容
D #删除 之前的内容,并跳转至脚本第一行,即/UNIX$/{处
}
备注:N是在模式空间追加一行,两行之间有一个分隔符 ;P是打印多行模式空间中第一个 之前的内容,也就是第一行;D是删除第一个 之前的内容,并使得控制流程跳转至脚本第一行,如果D后边还有命令,执行D后,后边的命令式执行不到的。
如果将脚本中替换命令那行换为以下一句,输出结果略有不同:
s/ System/ Operating System /
输出结果为:
Here are examples of the UNIX Operating System
.Where UNIX Operating System
appears, itshould be the UNIX
Operating System.
这里面有一些标点的问题,因此,我们做了特别处理,说明如下:
(System. *)代表System后边有一个任意字符,这是为了处理空格和句号的,后边*前边有个空格,这里看不出来,实际是输入了一个空格,这个代表,之后出现0个或多个空格,而其中用反斜杠和小括号括起来,代表后边1指的就是这个匹配。如果这里有不明白的,可以翻看前边关于()和1的介绍。
[h,H,g,G,x模式空间与备份空间命令]
这几个命令就是在两个空间中互相操作,比较好理解,这里不再举例。
[b,t]流程跳转命令,根据前边的理论介绍也比较好理解,不再举例。