sed (stream editor) 功能说明利用script来处理文本文件 语法sed [hnV][e<script>][f<script文件>][文本文件] 补充说明sed可依照script的指令来处理编辑文本文件 参数 e<script>或expression=<script> 以选项中指定的script来处理输入的文本文件 f<script文件>或file=<script文件> 以选项中指定的script文件来处理输入的文本文件 h或help 显示帮助 n或quiet或silent 仅显示script处理后的结果 V或version 显示版本信息 sed工作原理sed是一个非交互式的流编辑器所谓非交互式是指使用sed只能在命令行下输入编辑命令来编辑文本然后在屏幕上查看输出而所谓流编辑器是指sed每次只从文件(或输入)读入一行然后对该行进行指定的处理并将结果输出到屏幕(除非取消了屏幕输出又没有显式地使用打印命令)接着读入下一行整个文件像流水一样被逐行处理然后逐行输出 下面我们看一下sed的工作过程 sed不是在原输入上直接进行处理的而是先将读入的行放到缓沖区中对缓沖区里的内容进行处理处理完毕后也不会写回原文件(除非用shell的输出重定向来保存结果)而是直接输出到屏幕上sed运行过程中维护着两个缓沖区一个是活动的模式空间(pattern space)另一个是起辅助作用的暂存缓沖区(holding space)一般情况下每当运行sedsed首先把第一行装入模式空间进行处理后输出到屏幕然后将第二行装入模式空间替换掉模式空间里原来的内容然后进行处理以此类推 一般情况下暂存缓沖区是用不到的但有特殊的命令可以在模式空间与暂存缓沖区之间交换数据后文将有介绍由于sed对文本的所有操作都是在缓沖区里进行的所以不会对原文件造成任何破坏 sed命令格式 sed的命令格式如下 sed [Options] [Commands] filename 其中Command是一个sed命令sed命令一定要被包含在一对单引号中以免被shell解释其格式如下 [addressrange][sedcommand]或 [Patterntomatch][sedcommand] addressrange是指要处理的行的范围又叫地址范围patterntomatch是一个要匹配的模式是一个正则表达式sedcommand是一个sed命令用来对指定的行进行处理下面是一个简单的例子 sed –n p students 这个命令将文件students中的第到行打印到屏幕注意地址范围和sed命令之间没有空格如果加入空格sed也会将其忽略参数n用来取消默认输出默认情况下sed每读入一行到模式空间无论是否对其进行处理在读入下一行之前多要将模式空间中的内容输出到屏幕上参数n可以用来取消这种默认的输出只有当用户用命令p时才将指定的行输出到屏幕如果没有用参数n而又对指定行执行了p命令那么这些行将会被打印两次 地址范围可以是一个数字这个数字代表了一个行号也可以是一个用逗号分隔的两个数字表示的范围(包括这两行)范围可以是数字正则表达式或是两者的组合 patterntomatch是一个要匹配的模式sed将会对所有匹配的行执行sedcommand其实这里的patterntomatch也可以看作是一个地址这个地址是所有与指定模式匹配的行的行号因此sed的格式可以归纳为一种 sed [Options] [addressrange][sedcommand] filename 文本间隔 # 在每一行后面增加一空行 sed G # 将原来的所有空行删除并在每一行后面增加一空行 # 这样在输出的文本中每一行后面将有且只有一空行 sed /^$/d;G # 在每一行后面增加两行空行 sed G;G # 将第一个脚本所产生的所有空行删除(即删除所有偶[奇]数行) sed n;d # 在匹配式样regex的行之前插入一空行 sed /regex/{x;p;x;} # 在匹配式样regex的行之后插入一空行 sed /regex/G # 在匹配式样regex的行之前和之后各插入一空行 sed /regex/{x;p;x;G;} 编号 # 为文件中的每一行进行编号(简单的左对齐方式)这里使用了制表符 # (tab见本文末尾关于\t的用法的描述)而不是空格来对齐边缘 sed = filename | sed N;s/\n/\t/ # 对文件中的所有行编号(行号在左[上]文字右[左]端对齐) sed = filename | sed N; s/^/ /; s/ *\(\{\}\)\n/\ / # 对文件中的所有行编号但只显示非空白行的行号 sed //= filename | sed //N; s/\n/ / # 计算行数(模拟wc l) sed n $= 文本转换和替代 # Unix环境转换DOS的新行符(CR/LF)为Unix格式 sed s/$// # 假设所有行以CR/LF结束 sed s/^M$// # 在bash/tcsh中将按CtrlM改为按CtrlV sed s/\xD$// # ssedgsed 及更高版本 # Unix环境转换Unix的新行符(LF)为DOS格式 sed s/$/`echo e \\\r`/ # 在ksh下所使用的命令 sed s/$/`echo \\\r`/ # 在bash下所使用的命令 sed s/$/`echo \\\r`/ # 在zsh下所使用的命令 sed s/$/\r/ # gsed 及更高版本 # DOS环境转换Unix新行符(LF)为DOS格式 sed s/$// # 方法 sed n p # 方法 # DOS环境转换DOS新行符(CR/LF)为Unix格式 # 下面的脚本只对UnxUtils sed 及更高版本有效要识别UnxUtils版本的 # sed可以通过其特有的text选项你可以使用帮助选项(help)看 # 其中有无一个text项以此来判断所使用的是否是UnxUtils版本其它DOS # 版本的的sed则无法进行这一转换但可以用tr来实现这一转换 sed s/\r// infile >outfile # UnxUtils sed v 或更高版本 tr d \r <infile >outfile # GNU tr 或更高版本 # 将每一行前导的空白字符(空格制表符)删除 # 使之左对齐 sed s/^[ \t]*// # 见本文末尾关于\t用法的描述 # 将每一行拖尾的空白字符(空格制表符)删除 sed s/[ \t]*$// # 见本文末尾关于\t用法的描述 # 将每一行中的前导和拖尾的空白字符删除 sed s/^[ \t]*//;s/[ \t]*$// # 在每一行开头处插入个空格(使全文向右移动个字符的位置) sed s/^/ / # 以个字符为宽度将所有文本右对齐 sed e :a e s/^\{\}$/ &/;ta # 个字符外加最后的一个空格 # 以个字符为宽度使所有文本居中在方法中为了让文本居中每一行的前 # 头和后头都填充了空格在方法中在居中文本的过程中只在文本的前面填充 # 空格并且最终这些空格将有一半会被删除此外每一行的后头并未填充空格 sed e :a e s/^\{\}$/ & /;ta # 方法 sed e :a e s/^\{\}$/ &/;ta e s/\( *\)\/\/ # 方法 # 在每一行中查找字串foo并将找到的foo替换为bar sed s/foo/bar/ # 只替换每一行中的第一个foo字串 sed s/foo/bar/ # 只替换每一行中的第四个foo字串 sed s/foo/bar/g # 将每一行中的所有foo都换成bar sed s/\(*\)foo\(*foo\)/\bar\/ # 替换倒数第二个foo sed s/\(*\)foo/\bar/ # 替换最后一个foo # 只在行中出现字串baz的情况下将foo替换成bar sed /baz/s/foo/bar/g # 将foo替换成bar并且只在行中未出现字串baz的情况下替换 sed /baz/!s/foo/bar/g # 不管是scarletruby还是puce一律换成red sed s/scarlet/red/g;s/ruby/red/g;s/puce/red/g #对多数的sed都有效 gsed s/scarlet\|ruby\|puce/red/g # 只对GNU sed有效 # 倒置所有行第一行成为最后一行依次类推(模拟tac) # 由于某些原因使用下面命令时HHsed v会将文件中的空行删除 sed !G;h;$!d # 方法 sed n !G;h;$p # 方法 # 将行中的字符逆序排列第一个字成为最后一字……(模拟rev) sed /\n/!G;s/\(\)\(*\n\)/&\\/;//D;s/// # 将每两行连接成一行(类似paste) sed $!N;s/\n/ / # 如果当前行以反斜槓\结束则将下一行并到当前行末尾 # 并去掉原来行尾的反斜槓 sed e :a e /\\$/N; s/\\\n//; ta # 如果当前行以等号开头将当前行并到上一行末尾 # 并以单个空格代替原来行头的= sed e :a e $!N;s/\n=/ /;ta e P;D # 为数字字串增加逗号分隔符号将改为 gsed :a;s/\B[]\{\}\>/&/;ta # GNU sed sed e :a e s/\(*[]\)\([]\{\}\)/\\/;ta # 其他sed # 为带有小数点和负号的数值增加逗号分隔符(GNU sed) gsed r :a;s/(^|[^])([]+)([]{})/\\\/g;ta # 在每行后增加一空白行(在第等行后增加一空白行) gsed ~G # 只对GNU sed有效 sed n;n;n;n;G; # 其他sed 选择性地显示特定行 # 显示文件中的前行(模拟head的行为) sed q # 显示文件中的第一行(模拟head 命令) sed q # 显示文件中的最后行(模拟tail) sed e :a e $q;N;$D;ba # 显示文件中的最后行(模拟tail 命令) sed $!N;$!D # 显示文件中的最后一行(模拟tail ) sed $!d # 方法 sed n $p # 方法 # 显示文件中的倒数第二行 sed e $!{h;d;} e x # 当文件中只有一行时输入空行 sed e {$q;} e $!{h;d;} e x # 当文件中只有一行时显示该行 sed e {$d;} e $!{h;d;} e x # 当文件中只有一行时不输出 # 只显示匹配正则表达式的行(模拟grep) sed n /regexp/p # 方法 sed /regexp/!d # 方法 # 只显示不匹配正则表达式的行(模拟grep v) sed n /regexp/!p # 方法与前面的命令相对应 sed /regexp/d # 方法类似的语法 # 查找regexp并将匹配行的上一行显示出来但并不显示匹配行 sed n /regexp/{g;!p;};h # 查找regexp并将匹配行的下一行显示出来但并不显示匹配行 sed n /regexp/{n;p;} # 显示包含regexp的行及其前后行并在第一行之前加上regexp所 # 在行的行号(类似grep A B) sed n e /regexp/{=;x;!p;g;$!N;p;D;} e h # 显示包含AAABBB或CCC的行(任意次序) sed /AAA/!d; /BBB/!d; /CCC/!d # 字串的次序不影响结果 # 显示包含AAABBB和CCC的行(固定次序) sed /AAA*BBB*CCC/!d # 显示包含AAABBB或CCC的行(模拟egrep) sed e /AAA/b e /BBB/b e /CCC/b e d # 多数sed gsed /AAA\|BBB\|CCC/!d # 对GNU sed有效 # 显示包含AAA的段落(段落间以空行分隔) # HHsed v 必须在x;后加入G;接下来的个脚本都是这样 sed e //{H;$!d;} e x;/AAA/!d; # 显示包含AAABBB和CCC三个字串的段落(任意次序) sed e //{H;$!d;} e x;/AAA/!d;/BBB/!d;/CCC/!d # 显示包含AAABBBCCC三者中任一字串的段落(任意次序) sed e //{H;$!d;} e x;/AAA/b e /BBB/b e /CCC/b e d gsed //{H;$!d;};x;/AAA\|BBB\|CCC/b;d # 只对GNU sed有效 # 显示包含个或以上字符的行 sed n /^\{\}/p # 显示包含个以下字符的行 sed n /^\{\}/!p # 方法与上面的脚本相对应 sed /^\{\}/d # 方法更简便一点的方法 # 显示部分文本——从包含正则表达式的行开始到最后一行结束 sed n /regexp/$p # 显示部分文本——指定行号范围(从第至第行含和行) sed n p # 方法 sed !d # 方法 # 显示第行 sed n p # 方法 sed !d # 方法 sed q;d # 方法 处理大文件时更有效率 # 从第行开始每行显示一次 gsed n ~p # 只对GNU sed有效 sed n ${p;n;n;n;n;n;n;} # 其他sed # 显示两个正则表达式之间的文本(包含) sed n /Iowa//Montana/p # 区分大小写方式 选择性地删除特定行 # 显示通篇文档除了两个正则表达式之间的内容 sed /Iowa//Montana/d # 删除文件中相邻的重复行(模拟uniq) # 只保留重复行中的第一行其他行删除 sed $!N; /^\(*\)\n\$/!P; D # 删除文件中的重复行不管有无相邻注意hold space所能支持的缓存 # 大小或者使用GNU sed sed n G; s/\n/&&/; /^\([ ~]*\n\)*\n\/d; s/\n//; h; P # 删除除重复行外的所有行(模拟uniq d) sed $!N; s/^\(*\)\n\$/\/; t; D # 删除文件中开头的行 sed d # 删除文件中的最后一行 sed $d # 删除文件中的最后两行 sed N;$!P;$!D;$d # 删除文件中的最后行 sed e :a e $d;N;ba e P;D # 方法 sed n e :a e !{P;N;D;};N;ba # 方法 # 删除的倍数行 gsed ~d # 只对GNU sed有效 sed n;n;n;n;n;n;n;d; # 其他sed # 删除匹配式样的行 sed /pattern/d # 删除含pattern的行当然pattern # 可以换成任何有效的正则表达式 # 删除文件中的所有空行(与grep 效果相同) sed /^$/d # 方法 sed //!d # 方法 # 只保留多个相邻空行的第一行并且删除文件顶部和尾部的空行 # (模拟cat s) sed ///^$/!d #方法删除文件顶部的空行允许尾部保留一空行 sed /^$/N;/\n$/D #方法允许顶部保留一空行尾部不留空行 # 只保留多个相邻空行的前两行 sed /^$/N;/\n$/N;//D # 删除文件顶部的所有空行 sed //$!d # 删除文件尾部的所有空行 sed e :a e /^\n*$/{$d;N;ba e } # 对所有sed有效 sed e :a e /^\n*$/N;/\n$/ba # 同上但只对gsed *有效 # 删除每个段落的最后一行 sed n /^$/{p;h;};//{x;//p;} 特殊应用 # 移除手册页(man page)中的nroff标记在Unix System V或bash shell下使 # 用echo命令时可能需要加上e 选项 sed s/`echo \\\b`//g # 外层的双括号是必须的(Unix环境) sed s/^H//g # 在bash或tcsh中 按CtrlV 再按CtrlH sed s/\x//g # sed GNU sedssed所使用的十六进制的表示方法 # 提取新闻组或email 的邮件头 sed /^$/q # 删除第一行空行后的所有内容 # 提取新闻组或email 的正文部分 sed /^$/d # 删除第一行空行之前的所有内容 # 从邮件头提取Subject(标题栏字段)并移除开头的Subject:字样 sed /^Subject: */!d; s///;q # 从邮件头获得回复地址 sed /^ReplyTo:/q; /^From:/h; //d;g;q # 获取邮件地址在上一个脚本所产生的那一行邮件头的基础上进一步的将非电邮 # 地址的部分剃除(见上一脚本) sed s/ *(*)//; s/>*//; s/*[:<] *// # 在每一行开头加上一个尖括号和空格(引用信息) sed s/^/> / # 将每一行开头处的尖括号和空格删除(解除引用) sed s/^> // # 移除大部分的HTML标签(包括跨行标签) sed e :a e s/<[^>]*>//g;/</N;//ba # 将分成多卷的uuencode文件解码移除文件头信息只保留uuencode编码部分 # 文件必须以特定顺序传给sed下面第一种版本的脚本可以直接在命令行下输入 # 第二种版本则可以放入一个带执行权限的shell脚本中(由Rahul Dhesi的一 # 个脚本修改而来) sed /^end//^begin/d file file fileX | uudecode # vers sed /^end//^begin/d $@ | uudecode # vers # 将文件中的段落以字母顺序排序段落间以(一行或多行)空行分隔GNU sed使用 # 字元\v来表示垂直制表符这里用它来作为换行符的占位符——当然你也可以 # 用其他未在文件中使用的字符来代替它 sed //{H;d;};x;s/\n/={NL}=/g file | sort | sed s/={NL}=//;s/={NL}=/\n/g gsed //{H;d};x;y/\n/\v/ file | sort | sed s/\v//;y/\v/\n/ # 分别压缩每个TXT文件压缩后删除原来的文件并将压缩后的ZIP文件 # 命名为与原来相同的名字(只是扩展名不同)(DOS环境dir /b # 显示不带路径的文件名) echo @echo off >zipupbat dir /b *txt | sed s/^\(*\)\TXT/pkzip mo \ \TXT/ >>zipupbat 使用SEDSed接受一个或多个编辑命令并且每读入一行后就依次应用这些命令 当读入第一行输入后sed对其应用所有的命令然后将结果输出接着再读入第二行输入对其应用所有的命令……并重复这个过程上一个例子中sed由标准输入设备(即命令解释器通常是以管道输入的形式)获得输入在命令行给出一个或多个文件名作为参数时这些文件取代标准输入设备成为sed的输入sed的输出将被送到标准输出(显示器)因此 cat filename | sed q # 使用管道输入 sed q filename # 同样效果但不使用管道输入 sed q filename > newfile # 将输出转移(重定向)到磁盘上 要了解sed命令的使用说明包括如何通过脚本文件(而非从命令行)来使用这些命令请参阅《sed & awk》第二版作者Dale Dougherty和Arnold Robbins(OReilly)《UNIX Text Processing》 作者Dale Dougherty和Tim OReilly(Hayden Books)或者是Mike Arst写的教程——压缩包的名称是USEDITZIP(在许多站点上都找得到)要发掘sed的潜力则必须对正则表达式有足够的理解正则表达式的资料可以看《Mastering Regular Expressions》作者Jeffrey Friedl(Oreilly ) Unix系统所提供的手册页(man)也会有所帮助(试一下这些命令man sedman regexp或者看man ed中关于正则表达式的部分)但手册提供的信息比较抽象——这也是它一直为人所诟病的不过它本来就不是用来教初学者如何使用sed或正则表达式的教材而只是为那些熟悉这些工具的人提供的一些文本参考 括号语法前面的例子对sed命令基本上都使用单引号()而非双引号()这是因为sed通常是在Unix平台上使用单引号下Unix的shell(命令解释器)不会对美元符($)和后引号(``)进行解释和执行而在双引号下美元符会被展开为变量或参数的值后引号中的命令被执行并以输出的结果代替后引号中的内容而在csh及其衍生的shell中使用感歎号(!)时需要在其前面加上转义用的反斜槓(就像这样\!)以保证上面所使用的例子能正常运行(包括使用单引号的情况下)DOS版本的Sed则一律使用双引号()而不是引号来圈起命令 \t的用法为了使本文保持行文简洁我们在脚本中使用\t来表示一个制表符但是现在大部分版本的sed还不能识别\t的简写方式因此当在命令行中为脚本输入制表符时你应该直接按TAB键来输入制表符而不是输入\t下列的工具软件都支持\t做为一个正则表达式的字元来表示制表符awkperlHHsedsedmod以及GNU sed v 不同版本的SED不同的版本间的sed会有些不同之处可以想象它们之间在语法上会有差异具体而言它们中大部分不支持在编辑命令中间使用标签(:name)或分支命令(bt)除非是放在那些的末尾这篇文档中我们尽量选用了可移植性较高的语法以使大多数版本的sed的用户都能使用这些脚本不过GNU版本的sed允许使用更简洁的语法想像一下当读者看到一个很长的命令时的心情 sed e /AAA/b e /BBB/b e /CCC/b e d 好消息是GNU sed能让命令更紧凑 sed /AAA/b;/BBB/b;/CCC/b;d # 甚至可以写成 sed /AAA\|BBB\|CCC/b;d 此外请注意虽然许多版本的sed接受象/one/ s/RE/RE/这种在s前带有空 格的命令但这些版本中有些却不接受这样的命令:/one/! s/RE/RE/这时 只需要把中间的空格去掉就行了 速度优化当由于某种原因(比如输入文件较大处理器或硬盘较慢等)需要提高 命令执行速度时可以考虑在替换命令(s///)前面加上地址表达式来 提高速度举例来说 sed s/foo/bar/g filename # 标准替换命令 sed /foo/ s/foo/bar/g filename # 速度更快 sed /foo/ s//bar/g filename # 简写形式 当只需要显示文件的前面的部分或需要删除后面的内容时可以在脚本中使用q 命令(退出命令)在处理大的文件时这会节省大量时间因此 sed n p filename # 显示第到行 sed n q;p filename # 一样但快得多 如果你有其他的单行脚本想与大家分享或者你发现了本文档中错误的地方请发电子邮件给本文档的作者(Eric Pement)邮件中请记得提供你所使用的sed版本该sed所运行的操作系统及对问题的适当描述本文所指的单行脚本指命令行的长度在个字符或个以下的sed脚本〔译注〕 译注大部分情况下sed脚本无论多长都能写成单行的形式(通过`e选项和`;号)——只要命令解释器支持所以这里说的单行脚本除了能写成一行还对长度有所限制因为这些单行脚本的意义不在于它们是以单行的形式出现而是让用户能方便地在命令行中使用这些紧凑的脚本才是其意义所在 |