shell基础二十篇

这里是其中的第十章 sed.  其他各章可察看相应的 link.  

shell基础1:文件安全与权限 
http://bbs.chinaunix.net/thread-434579-1-1.html

附:Linux的用户和用户组管理 
http://bbs.chinaunix.net/thread-438660-1-1.html

shell基础二:查找技巧,find及xargs的使用
http://bbs.chinaunix.net/thread-441883-1-1.html

shell基础三和四:后台(crontab,at,&,nohup)及(*,?,[]等) 
http://bbs.chinaunix.net/thread-442596-1-1.html

shell基础五:输入和输出(echo,read,cat,管道,tee,重定向等) 
http://bbs.chinaunix.net/thread-444209-1-1.html

shell基础六七:命令执行顺序(||及&&,{}及())和正则表? 
http://bbs.chinaunix.net/thread-445229-1-1.html

shell基础八:文本过滤工具(grep) 
http://bbs.chinaunix.net/thread-446683-1-1.html

shell基础九:awk 
http://bbs.chinaunix.net/thread-448687-1-1.html

shell基础十:sed 
http://bbs.chinaunix.net/thread-452942-1-1.html

shell基础11:文件分类、合并和分割(sort,uniq,join,cut,paste,split) 
http://bbs.chinaunix.net/thread-457730-1-1.html

shell基础十二:tr 
http://bbs.chinaunix.net/thread-459099-1-1.html

感谢L_kernel补充的第十三——二十篇(cjaizss添加)
shell基础第十三篇-登录环境 
http://bbs.chinaunix.net/thread-1820174-1-1.html

shell基础第十四篇-环境和shell变量 
http://bbs.chinaunix.net/thread-1820194-1-1.html

shell基础第十五篇-引号
http://bbs.chinaunix.net/thread-1820220-1-1.html

shell基础第十六篇-shell脚本介绍
http://bbs.chinaunix.net/thread-1820301-1-1.html

shell基础学习第十七篇-条件测试 
http://bbs.chinaunix.net/thread-1820304-1-1.html

shell基础第十八篇-控制流结构 
http://bbs.chinaunix.net/thread-1820329-1-1.html

shell学习基础第十九篇-shell函数
http://bbs.chinaunix.net/thread-1820454-1-1.html

shell基础学习第二十篇-向脚本传递参数 
http://bbs.chinaunix.net/thread-1823335-1-1.html

其它我的笔记都在我的BLOG上,呵呵,有兴趣的可以去看看

sed链接:http://bbs.chinaunix.net/thread-452942-1-1.html   

shell基础十:sed


sed 用法介绍

s e d是一个非交互性文本流编辑器。它编辑文件或标准输入导出的文本拷贝。

" 抽取域。
" 匹配正则表达式。
" 比较域。
" 增加、附加、替换。
" 基本的s e d命令和一行脚本。


可以在命令行输入s e d命令,也可以在一个文件中写入命令,然后调用s e d,这与a w k基本相同。使用s e d需要记住的一个重要事实是,无论命令是什么, s e d并不与初始化文件打交道,它操作的只是一个拷贝,然后所有的改动如果没有重定向到一个文件,将输出到屏幕。

因为s e d是一个非交互性编辑器,必须通过行号或正则表达式指定要改变的文本行。
本文介绍s e d用法和功能。本章大多编写的是一行命令和小脚本。这样做可以慢慢加深对s e d用法的了解,取得宝贵的经验,以便最终自己编出大的复杂s e d脚本。
和g r e p与a w k一样, s e d是一种重要的文本过滤工具,或者使用一行命令或者使用管道与g r e p与a w k相结合。

1 sed怎样读取数据

s e d从文件的一个文本行或从标准输入的几种格式中读取数据,将之拷贝到一个编辑缓冲区,然后读命令行或脚本的第一条命令,并使用这些命令查找模式或定位行号编辑它。重复此过程直到命令结束。

2 调用sed

调用s e d有三种方式:在命令行键入命令;将s e d命令插入脚本文件,然后调用s e d;将s e d命令插入脚本文件,并使s e d脚本可执行。

使用s e d命令行格式为:
  1. sed [选项] s e d命令输入文件。
复制代码记住在命令行使用s e d命令时,实际命令要加单引号。s e d也允许加双引号。

使用s e d脚本文件,格式为:
  1. sed [选项] -f sed脚本文件输入文件
复制代码要使用第一行具有s e d命令解释器的s e d脚本文件,其格式为:
  1. s e d脚本文件[选项] 输入文件
复制代码不管是使用s h e l l命令行方式或脚本文件方式,如果没有指定输入文件, s e d从标准输入中接受输入,一般是键盘或重定向结果。
 
s e d选项如下:
n 不打印;s e d不写编辑行到标准输出,缺省为打印所有行(编辑和未编辑)。p命令可以用来打印编辑行。
c 下一命令是编辑命令。使用多项编辑时加入此选项。如果只用到一条s e d命令,此选项无用,但指定它也没有关系。
f 如果正在调用s e d脚本文件,使用此选项。此选项通知s e d一个脚本文件支持所有的s e d命令,例如:sed -f myscript.sed input_file,这里m y s c r i p t . s e d即为支持s e d命令的文件。


2.1 保存sed输出
由于不接触初始化文件,如果想要保存改动内容,简单地将所有输出重定向到一个文件即可。下面的例子重定向s e d命令的所有输出至文件‘ m y o u t f i l e’,当对结果很满意时使用这种方法。
  1. $sed 'some-sed-commands' input-file > myoutfile
复制代码2.2 使用sed在文件中查询文本的方式
s e d浏览输入文件时,缺省从第一行开始,有两种方式定位文本:
1) 使用行号,可以是一个简单数字,或是一个行号范围。
2 ) 使用正则表达式


下面是使用s e d定位文本的一些方式。
  1. x x为一行号,如1
  2. x , y 表示行号范围从x到y,如2,5表示从第2行到第5行
  3. / p a t t e r n / 查询包含模式的行。例如/ d i s k /或/[a-z]/
  4. / p a t t e r n / p a t t e r n / 查询包含两个模式的行。例如/ d i s k / d i s k s /
  5. p a t t e r n / , x 在给定行号上查询包含模式的行。如/ r i b b o n / , 3
  6. x , / p a t t e r n / 通过行号和模式查询匹配行。3 . / v d u /
  7. x , y ! 查询不包含指定行号x和y的行。1 , 2 !
复制代码2.3 基本sed编辑命令
  1. sed编辑命令
  2. p 打印匹配行
  3. = 显示文件行号
  4. a \ 在定位行号后附加新文本信息
  5. i \ 在定位行号后插入新文本信息
  6. d 删除定位行
  7. c \ 用新文本替换定位文本
  8. s 使用替换模式替换相应模式
  9. r 从另一个文件中读文本
  10. w 写文本到一个文件
  11. q 第一个模式匹配完成后推出或立即推出
  12. l 显示与八进制A S C I I代码等价的控制字符
  13. { } 在定位行执行的命令组
  14. n 从另一个文件中读文本下一行,并附加在下一行
  15. g 将模式2粘贴到/pattern n/
  16. y 传送字符
  17. n 延续到下一输入行;允许跨行的模式匹配语句
复制代码sed和正则表达式

s e d识别任何基本正则表达式和模式及其行匹配规则。记住规则之一是:如果要定位一特殊字符,必须使用( \)屏蔽其特殊含义

 
 
  
 

 

shell基础十二篇

链接:http://www.chinalinuxpub.com/doc/oreillybookself/unix/sedawk/index.htm 
s e d例子中使用下述文本文件q u o t e . t x t。
  1. [sam@Linux_chenwy sam]$ cat quote.txt
  2. The honeysuckle band played all night long for only $90.
  3. It was an evening of splendid music and company.
  4. Too bad the disco floor fell through at 23:00.
  5. The local nurse Miss P.Neave was in attendance.
复制代码

1 使用p(rint)显示行
只打印第二行,用-n
  1. [sam@Linux_chenwy sam]$ sed -n '2p' quote.txt
  2. It was an evening of splendid music and company.
复制代码

2 打印范围
可以指定行的范围,现打印1到3行,用逗号分隔行号。
  1. [sam@Linux_chenwy sam]$ sed -n '1,3p' quote.txt
  2. The honeysuckle band played all night long for only $90.
  3. It was an evening of splendid music and company.
  4. Too bad the disco floor fell through at 23:00.
复制代码

3 打印模式
假定要匹配单词N e a v e,并打印此行,方法如下。使用模式/ p a t t e r n /格式,这里为/ N e a v e /。
  1. [sam@Linux_chenwy sam]$ sed -n '/The/p' quote.txt
  2. The honeysuckle band played all night long for only $90.
  3. The local nurse Miss P.Neave was in attendance.
复制代码

4 使用模式和行号进行查询
可以将行号和模式结合使用。假定要改动文件q u o t e . t x t最后一行中的单词t h e,使用s e d查询t h e,返回两行:
  1. [sam@Linux_chenwy sam]$ sed -n '/The/p' quote.txt
  2. The honeysuckle band played all night long for only $90.
  3. The local nurse Miss P.Neave was in attendance.
复制代码

使用模式与行号的混合方式可以剔除第一行,格式为l i n e _ n u m b e r, / p a t t e r n /。逗号用来分隔行号与模式开始部分。为达到预期结果,使用4 , / t h e /。意即只在第四行查询模式t h e,命令如下:
  1. [sam@Linux_chenwy sam]$ sed -n '4,/The/p' quote.txt
  2. The local nurse Miss P.Neave was in attendance.
复制代码
上面有错,其实是把第四行后的都打出来了
这个模式应该哪果指定行找不到符合条件的,就从下一行开始查找,直到找到为止,并把,找到行之前的全部打打印出来。
如果指定行本身就符合条伯,把本行及后面的行的全部打印出来


5 匹配元字符
匹配元字符$前,必须使用反斜线\屏蔽其特殊含义。模式为/\$/ p。
  1. [sam@Linux_chenwy sam]$ sed -n '/\$/p' quote.txt
  2. The honeysuckle band played all night long for only $90.
复制代码

6 显示整个文件
要打印整个文件,只需将行范围设为第一行到最后一行1 , $。$意为最后一行。
  1. [sam@Linux_chenwy sam]$ sed -n '1,$p' quote.txt
  2. The honeysuckle band played all night long for only $90.
  3. It was an evening of splendid music and company.
  4. Too bad the disco floor fell through at 23:00.
  5. The local nurse Miss P.Neave was in attendance.
复制代码

7 任意字符
匹配任意字母,后跟任意字母的0次或多次重复,并以i n g结尾,模式为/ . * i n g /。可以使用这个模式查询以i n g结尾的任意单词。
  1. [sam@Linux_chenwy sam]$ sed -n '/.*ing/p' quote.txt
  2. It was an evening of splendid music and company.
复制代码

8 首行
要打印文件第一行,使用行号:
  1. [sam@Linux_chenwy sam]$ sed -n '1p' quote.txt
  2. The honeysuckle band played all night long for only $90.
复制代码

9 最后一行
要打印最后一行,使用$。$是代表最后一行的元字符。
  1. [sam@Linux_chenwy sam]$ sed -n '$p' quote.txt
  2. The local nurse Miss P.Neave was in attendance.
复制代码

10 打印行号
要打印行号,使用等号=。打印模式匹配的行号,使用格式/ p a t t e r n / =。
  1. [sam@Linux_chenwy sam]$ sed -e '/music/=' quote.txt
  2. The honeysuckle band played all night long for only $90.
  3. 2
  4. It was an evening of splendid music and company.
  5. Too bad the disco floor fell through at 23:00.
  6. The local nurse Miss P.Neave was in attendance.
复制代码

整个文件都打印出来,并且匹配行打印了行号。如果只关心实际行号,使用- e选项。
  1. [sam@Linux_chenwy sam]$ sed -n '/music/=' quote.txt
  2. 2
复制代码

如果只打印行号及匹配行,必须使用两个s e d命令,并使用e选项。第一个命令打印模式匹配行,第二个使用=选项打印行号,格式为sed -n -e /pattern/p -e /pattern/=
  1. [sam@Linux_chenwy sam]$ sed -n -e '/music/p' -e '/music/='  quote.txt
  2. It was an evening of splendid music and company.
  3. 2

复制代码

11 附加文本

要附加文本,使用符号a \,可以将指定文本一行或多行附加到指定行。如果不指定文本放置位置, s e d缺省放在每一行后面。附加文本时不能指定范围,只允许一个地址模式。文本附加操作时,结果输出在标准输出上。注意它不能被编辑,因为s e d执行时,首先将文件的一行文本拷贝至缓冲区,在这里s e d编辑命令执行所有操作(不是在初始文件上),因为文本直接输出到标准输出,s e d并无拷贝。
要想在附加操作后编辑文本,必须保存文件,然后运行另一个s e d命令编辑它。这时文件的内容又被移至缓冲区。
附加操作格式如下:

  1. [address]a\
  2. text\
  3. text\
  4. ......
  5. text

复制代码
地址指定一个模式或行号,定位新文本附加位置。a\ 通知s e d对a \后的文本进行实际附加操作。观察格式,注意每一行后面有一斜划线,这个斜划线代表换行。s e d执行到这儿,将创建一新行,然后插入下一文本行。最后一行不加斜划线, s e d假定这是附加命令结尾。

当附加或插入文本或键入几个s e d命令时,可以利用辅助的s h e l l提示符以输入多行命令。当附加或插入文本或键入几个s e d命令时,可以利用辅助的s h e l l提示符以输入多行命令。

创建sed脚本文件

创建脚本文件a p p e n d . s e d:
第一行是s e d命令解释行。脚本在这一行查找s e d以运行命令,这里定位在/ b i n。
第二行以/ c o m p a n y /开始,这是附加操作起始位置。a \通知s e d这是一个附加操作,首先应插入一个新行。
第三行是附加操作要加入到拷贝的实际文本。
输出显示附加结果。如果要保存输出,重定向到一个文件。

  1. [sam@chenwy sam]$ cat append.sed
  2. #!/bin/sed -f
  3. /company/ a\
  4. Then suddenly it happed.

复制代码


保存它,增加可执行权限,运行


使用替换修改字符串
如果要附加或修改一个字符串,可以使用(&)命令,&命令保存发现模式以便重新调用它,然后把它放在替换字符串里面。
先给出一个被替换模式,然后是一个准备附加在第一个模式后的另一个模式,并且后面带有&,这样修改模式将放在匹配模式之前。
例如, s e d语句s/nurse/"Hello"&/p 的结果如下
  1. [sam@chenwy sam]$ sed -n 's/nurse/"hello" &/p' quote.txt
  2. The local "hello" nurse Miss P.Neave was in attendance.
复制代码
原句是文本行The local nurse Miss P.Neave was in attendance。
记住模式中要使用空格,因为输出结果表明应加入空格。

还有一个例子:
  1. [sam@chenwy sam]$ sed -n 's/played/from Hockering &/p' quote.txt
  2. The honeysuckle band from Hockering played all night long for only $90.
复制代码
原句是The honeysuckle band played all night long for only $90。

将sed结果写入文件命令
像使用>文件重定向发送输出到一个文件一样,在s e d命令中也可以将结果输入文件。格式有点像使用替换命令:
  1. [ a d d r e s s [,address]]w filename
复制代码
‘w’选项通知s e d将结果写入文件。f i l e n a m e是自解释文件名。
下面有两个例子。
  1. [sam@chenwy sam]$ sed '1,2 w filedt' quote.txt
  2. The honeysuckle band played all night long for only $90.
  3. It was an evening of splendid music and company.
  4. Too bad the disco floor fell through at 23:00.
  5. The local nurse Miss P.Neave was in attendance.
复制代码

文件q u o t e . t x t输出到屏幕。模式范围即1,2行输出到文件f i l e d t。
  1. [sam@chenwy sam]$ cat filedt
  2. The honeysuckle band played all night long for only $90.
  3. It was an evening of splendid music and company.
复制代码

下面例子中查询模式N e a v e,匹配结果行写入文件f i l e d h t。
  1. [sam@chenwy sam]$ sed '/Neave/ w dht' quote.txt
  2. The honeysuckle band played all night long for only $90.
  3. It was an evening of splendid music and company.
  4. Too bad the disco floor fell through at 23:00.
  5. The local nurse Miss P.Neave was in attendance.
复制代码
  1. [sam@chenwy sam]$ cat dht
  2. The local nurse Miss P.Neave was in attendance.
复制代码


从文件中读文本
处理文件时, s e d允许从另一个文件中读文本,并将其文本附加在当前文件。此命令放在模式匹配行后,格式为:
  1. address r filename
复制代码
这里r通知s e d将从另一个文件源中读文本。f i l e n a m e是其文件名。

现在创建一个小文件s e d e x . t x t,内容如下:
  1. [sam@chenwy sam]$ echo "Boom boom went the music" >sedex.txt
  2. [sam@chenwy sam]$ cat sedex.txt
  3. Boom boom went the music
复制代码

将s e d e x . t x t内容附加到文件q u o t e . t x t的拷贝。在模式匹配行/ c o m p a n y /后放置附加文本。本例为第三行。注意所读的文件名需要用单引号括起来。
  1. [sam@chenwy sam]$ sed '/company./r sedex.txt' quote.txt
  2. The honeysuckle band played all night long for only $90.
  3. It was an evening of splendid music and company.
  4. Boom boom went the music
  5. Too bad the disco floor fell through at 23:00.
  6. The local nurse Miss P.Neave was in attendance.
复制代码


匹配后退出
有时需要在模式匹配首次出现后退出s e d,以便执行其他处理脚本。退出命令格式为:
  1. address q
复制代码
下面的例子假定查询模式/ . a . * /,意为任意字符后跟字符a,再跟任意字符0次或任意多次。
查询首次出现模式,然后退出。需要将q放在s e d语句末尾。
  1. [sam@chenwy sam]$ sed '/.a.*/q' quote.txt
  2. The honeysuckle band played all night long for only $90.
复制代码
显示文件中的控制字符

1、$vi dos.txt
进入vi后,用ctrl+v 再用ctrl+M产生控制字符^M不知对不对


使用cat -v filename命令查看编辑好的文件
  1. [sam@chenwy sam]$ cat -v dos.txt
  2. 12332##DISO##45.12^M
  3. 00332##LPSO##23.14^M
  4. 01299##USPD##34.46^M
复制代码

s e d格式为:
  1. [ a d d r e s s,[ a d d r e s s ] ] l
复制代码
‘l’意为列表。一般情况下要列出整个文件,而不是模式匹配行,因此使用l要从第一到最后一行。模式范围1,$即为此意。
  1. [sam@chenwy sam]$ sed -n '1,$l' dos.txt
  2. 12332##DISO##45.12\r$
  3. 00332##LPSO##23.14\r$
  4. 01299##USPD##34.46\r$
复制代码

处理控制字符
使用s e d实现的一个重要功能是在另一个系统中下载的文件中剔除控制字符。
下面是传送过来的文件( d o s . t x t)的部分脚本。必须去除所有可疑字符,以便于帐号所有者使用文件。

删除所有的#字符很容易,可以使用全局替换命令。这里用一个空格替换两个或
更多的#符号。
  1. [sam@chenwy sam]$ sed 's/##/ /g' dos.txt
  2. 12332 DISO 45.12
  3. 00332 LPSO 23.14
  4. 01299 USPD 34.46
复制代码

。删除所有行首的0。使用^符号表示模式从行首开始, ^ 0 *表示行首任意个0。模式s / ^ 0 * / / g设置替换部分为空,即为删除模式,正是要求所在。
  1. [sam@chenwy sam]$ sed 's/##/ /g;s/^0*/ /g' dos.txt
  2. 12332 DISO 45.12
  3. 332 LPSO 23.14
  4. 1299 USPD 34.46
复制代码

最后去除行尾^ M符号,为此需做全局替换。设置替换部分为空。模式为:
‘s / ^ m / / g’,注意‘^ M’,这是一个控制字符。
在命令行里也必须用^M控制字符耶!?
  1. [sam@chenwy sam]$ sed 's/##/ /g;s/^0*/ /g;s/^M/ /g' dos.txt
  2. 12332 DISO 45.12
  3. 332 LPSO 23.14
  4. 1299 USPD 34.46
复制代码

  1. [sam@chenwy sam]$ cat dos.txt | sed 's/^0*/ /g' | sed 's/^M/ /g' | sed 's/##/ /g'

复制代码

 

处理报文输出
当从数据库中执行语句输出时,一旦有了输出结果,脚本即可做进一步处理。通常先做一些整理,下面是一个s q l查询结果。
  1. [sam@chenwy sam]$ cat data.txt
  2. Database Size(MB) DataCreated
  3. -----------------------------
  4. GOSOUTH  2244     12/11/97
  5. TRISUD   5632     8/9/99
  6. (2 rows affected)
复制代码

为了使用上述输出信息做进一步自动处理,需要知道所存数据库名称,为此需执行以下
操作:
1) 使用s / - * / / g删除横线- - - - - -。
2) 使用/ ^ $ / d删除空行。
3) 使用$ d删除最后一行
4) 使用1 d删除第一行。
5) 使用awk {print $1}打印第一列。
命令如下,这里使用了c a t,并管道传送结果到s e d命令。
  1. [sam@chenwy sam]$ cat data.txt |sed 's/--*/ /g' | sed '/^$/d' | sed '$d' | sed '1d' | awk '{print $1}'
  2. GOSOUTH
  3. TRISUD
复制代码

附加文本
当帐户完成设置一个文件时,帐号管理者可能要在文件中每个帐号后面加一段文字,下面是此类文件的一部分:
  1. [sam@chenwy sam]$ cat ok.txt
  2. AC456
  3. AC492169
  4. AC9967
  5. AC88345
复制代码

任务是在每一行末尾加一个字符串‘ p a s s e d’。
使用$命令修改各域会使工作相对容易些。首先需要匹配至少两个或更多的数字重复出现,这样将所有的帐号加进匹配模式。
  1. [sam@chenwy sam]$ sed 's/[0-9][0-9]*/& Passed/g' ok.txt
  2. AC456 Passed
  3. AC492169 Passed
  4. AC9967 Passed
  5. AC88345 Passed
复制代码

从shell向sed传值
要从命令行中向s e d传值,值得注意的是用双引号,否则功能不执行。
  1. [sam@chenwy sam]$ NAME="It's a go situation"
  2. [sam@chenwy sam]$ REPLACE="GO"
  3. [sam@chenwy sam]$ echo $NAME | sed "s/go/$REPLACE/g"
  4. It's a GO situation
复制代码

从sed输出中设置shell变量
从s e d输出中设置s h e l l变量是一个简单的替换过程。运用上面的例子,创建s h e l l变量N E W- N A M E,保存上述s e d例子的输出结果。
  1. [sam@chenwy sam]$ NAME="It's a go situation"
  2. [sam@chenwy sam]$ REPLACE="GO"
  3. [sam@chenwy sam]$ NEW_NAME=`echo $NAME | sed "s/go/$REPLACE/g"`
  4. [sam@chenwy sam]$ echo $NEW_NAME
  5. It's a GO situation
复制代码
这里的`是键盘左上角那个`


下面是一些一行命令集。([ ]表示空格, [ ]表示t a b键)
‘s / \ . $ / / g’ 删除以句点结尾行
‘-e /abcd/d’ 删除包含a b c d的行
‘s / [ ] [ ] [ ] * / [ ] / g’ 删除一个以上空格,用一个空格代替
‘s / ^ [ ] [ ] * / / g’ 删除行首空格
‘s / \ . [ ] [ ] * / [ ] / g’ 删除句点后跟两个或更多空格,代之以一个空格
‘/ ^ $ / d’ 删除空行
‘s / ^ . / / g’ 删除第一个字符
‘s /CO L \ ( . . . \ ) / / g’ 删除紧跟C O L的后三个字母
‘s / ^ \ / / / g’ 从路径中删除第一个\
‘s / [ ] / [ ] / / g’ 删除所有空格并用t a b键替代
‘S / ^ [ ] / / g’ 删除行首所有t a b键
‘s / [ ] * / / g’ 删除所有t a b键


1. 删除路径名第一个\符号
将当前工作目录返回给s e d,删除第一个\:
  1. [sam@chenwy sam]$ echo $PWD |sed 's/^\///g'
  2. usr/sam
复制代码

2. 追加/插入文本
将"Mr Wi l l i s "字串返回给s e d并在M r后而追加" B r u c e "。
  1. [sam@chenwy sam]$ echo "Mr Willis" |sed 's/Mr /& Bruce/g'
  2. Mr  BruceWillis
复制代码

3. 删除首字符
s e d删除字符串“a c c o u n t s . d o c”首字符。
  1. [sam@chenwy sam]$ echo "accounts.doc" |sed 's/^.//g'
  2. ccounts.doc
复制代码

4. 删除文件扩展名
s e d删除“a c c o u n t s . d o c”文件扩展名。
  1. [sam@chenwy sam]$ echo "accounts.doc"|sed 's/.doc//g'
  2. accounts
复制代码

5. 增加文件扩展名
s e d附加字符串“. d o c”到字符串“a c c o u n t s”。
  1. [sam@chenwy sam]$ echo "accounts"|sed 's/$/.doc/g'
  2. accounts.doc
复制代码

6. 替换字符系列
如果变量x含有下列字符串:
  1. [sam@chenwy sam]$ x="Department+playroll&Building G"
  2. [sam@chenwy sam]$ echo $x
  3. Department+playroll&Building G
复制代码

如果要加入of,located,并去掉+,&实现下列转换:
  1. [sam@chenwy sam]$ echo $x |sed 's/\+/ of /g' |sed 's/\&/ Located at /g'
  2. Department of playroll Located at Building G
复制代码
把+用 of 替换,&用located at 替换
 

常见问题

1、在上面中,vi如何产生控制字符( ^ M)?
ctrl+v然后ctrl+我想要的字符对不对?
2、如何替换控制字符,ctrl+v+M试一试

 

sed完


挑选编辑器
在 UNIX 世界中有很多文本编辑器可供我们选择。思考一下 -- vi、emacs 和 jed 以及很多其它工具都会浮现在脑海中。我们都有自己已逐渐了解并且喜爱的编辑器(以及我们喜爱的组合键)。有了可信赖的编辑器,我们可以轻松处理任何数量与 UNIX 有关的管理或编程任务。

虽然交互式编辑器很棒,但却有其限制。尽管其交互式特性可以成为强项,但也有其不足之处。考虑一下需要对一组文件执行类似更改的情形。您可能会本能地运行自己所喜爱的编辑器,然后手工执行一组烦琐、重复和耗时的编辑任务。然而,有一种更好的方法。

进入 sed
如果可以使编辑文件的过程自动化,以便用“批处理”方式编辑文件,甚至编写可以对现有文件进行复杂更改的脚本,那将太好了。幸运的是,对于这种情况,有一种更好的方法 -- 这种更好的方法称为 "sed"。

sed 是一种几乎包括在所有 UNIX 平台(包括 Linux)的轻量级流编辑器。sed 有许多很好的特性。首先,它相当小巧,通常要比您所喜爱的脚本语言小很多倍。其次,因为 sed 是一种流编辑器,所以,它可以对从如管道这样的标准输入接收的数据进行编辑。因此,无需将要编辑的数据存储在磁盘上的文件中。因为可以轻易将数据管道输出到 sed,所以,将 sed 用作强大的 shell 脚本中长而复杂的管道很容易。试一下用您所喜爱的编辑器去那样做。

GNU sed
对 Linux 用户来说幸运的是,最好的 sed 版本之一恰好是 GNU sed,其当前版本是 3.02。每一个 Linux 发行版都有(或至少应该有)GNU sed。GNU sed 之所以流行不仅因为可以自由分发其源代码,还因为它恰巧有许多对 POSIX sed 标准便利、省时的扩展。另外,GNU 没有 sed 早期专门版本的很多限制,如行长度限制 -- GNU 可以轻松处理任意长度的行。

最新的 GNU sed
在研究这篇文章之时我注意到:几个在线 sed 爱好者提到 GNU sed 3.02a。奇怪的是,在ftp.gnu.org(有关这些链接,请参阅参考资料)上找不到 sed 3.02a,所以,我只得在别处寻找。我在alpha.gnu.org 的 /pub/sed 中找到了它。于是我高兴地将其下载、编译然后安装,而几分钟后我发现最新的 sed 版本却是 3.02.80 -- 可在alpha.gnu.org 上 3.02a 源代码旁边找到其源代码。安装完 GNU sed 3.02.80 之后,我就完全准备好了。

alpha.gnu.org
alpha.gnu.org(请参阅参考资料)是新的和实验性 GNU 源代码的所在地。然而,您还会在那里发现许多优秀、稳定的源代码。出于某种原因,不是许多 GNU 开发人员忘记将稳定的源代码移至 ftp.gnu.org,就是它们的 "beta" 期间格外长(2 年!)。例如,sed 3.02a 已有两年,甚至 3.02.80 也有一年,但它们仍不能(在 2000 年 8 月写本文章时)在 ftp.gnu.org 上获得。

正确的 sed
在本系列中,将使用 GNU sed 3.02.80。在即将出现的本系列后续文章中,某些(但非常少)最高级的示例将不能在 GNU sed 3.02 或 3.02a 中使用。如果您使用的不是 GNU sed,那么结果可能会不同。现在为什么不花些时间安装 GNU sed 3.02.80 呢?那样,不仅可以为本系列的余下部分作好准备,而且还可以使用可能是目前最好的 sed。


sed 示例
sed 通过对输入数据执行任意数量用户指定的编辑操作(“命令”)来工作。sed 是基于行的,因此按顺序对每一行执行命令。然后,sed 将其结果写入标准输出 (stdout),它不修改任何输入文件。
让我们看一些示例。头几个会有些奇怪,因为我要用它们演示 sed 如何工作,而不是执行任何有用的任务。然而,如果您是 sed 新手,那么理解它们是十分重要的。下面是第一个示例:
 
  1. $ sed -e 'd' /etc/services
复制代码

如果输入该命令,将得不到任何输出。那么,发生了什么?
在该例中,用一个编辑命令 'd' 调用 sed。sed 打开 /etc/services 文件,将一行读入其模式缓冲区,执行编辑命令(“删除行”),然后打印模式缓冲区(缓冲区已为空)。然后,它对后面的每一行重复这些步骤。这不会产生输出,因为 "d" 命令除去了模式缓冲区中的每一行!

在该例中,还有几件事要注意。首先,根本没有修改 /etc/services。这还是因为 sed 只读取在命令行指定的文件,将其用作输入 -- 它不试图修改该文件。第二件要注意的事是 sed 是面向行的。'd' 命令不是简单地告诉 sed 一下子删除所有输入数据。相反,sed 逐行将 /etc/services 的每一行读入其称为模式缓冲区的内部缓冲区。一旦将一行读入模式缓冲区,它就执行 'd' 命令,然后打印模式缓冲区的内容(在本例中没有内容)。我将在后面为您演示如何使用地址范围来控制将命令应用到哪些行 -- 但是,如果不使用地址,命令将应用到所有行。

第三件要注意的事是括起 'd' 命令的单引号的用法。养成使用单引号来括起 sed 命令的习惯是个好注意,这样可以禁用 shell 扩展。

另一个 sed 示例
下面是使用 sed 从输出流除去 /etc/services 文件第一行的示例:
 
  1. $ sed -e '1d' /etc/services | more
复制代码



地址范围
现在,让我们看一下如何指定地址范围。在本例中,sed 将删除输出的第 1 到 10 行:
  1. $ sed -e '1,10d' /etc/services | more
复制代码

当用逗号将两个地址分开时,sed 将把后面的命令应用到从第一个地址开始、到第二个地址结束的范围。在本例中,将 'd' 命令应用到第 1 到 10 行(包括这两行)。所有其它行都被忽略。


带规则表达式的地址
现在演示一个更有用的示例。假设要查看 /etc/services 文件的内容,但是对查看其中包括的注释部分不感兴趣。如您所知,可以通过以 '#' 字符开头的行在 /etc/services 文件中放置注释。为了避免注释,我们希望 sed 删除以 '#' 开始的行。以下是具体做法:
 
  1. $ sed -e '/^#/d' /etc/services | more
复制代码

让我们分析发生的情况。

要理解 '/^#/d' 命令,首先需要对其剖析。首先,让我们除去 'd' -- 这是我们前面所使用的同一个删除行命令。新增加的是 '/^#/' 部分,它是一种新的规则表达式地址。规则表达式地址总是由斜杠括起。它们指定一种 模式,紧跟在规则表达式地址之后的命令将仅适用于正好与该特定模式匹配的行。

因此,'/^#/' 是一个规则表达式。但是,它做些什么呢?很明显,现在该复习规则表达式了。

规则表达式复习
可以使用规则表达式来表示可能会在文本中发现的模式。您在 shell 命令行中用过 '*' 字符吗?这种用法与规则表达式类似,但并不相同。下面是可以在规则表达式中使用的特殊字符:
 
字符 描述 
与行首匹配 
与行末尾匹配 
与任一个字符匹配 
将与前一个字符的零或多个出现匹配 
[ ] 与 [ ] 之内的所有字符匹配


感受规则表达式的最好方法可能是看几个示例。所有这些示例都将被 sed 作为合法地址接受,这些地址出现在命令的左边。下面是几个示例:
 
规则
表达式 描述 
/./ 将与包含至少一个字符的任何行匹配 
/../ 将与包含至少两个字符的任何行匹配 
/^#/ 将与以 '#' 开始的任何行匹配 
/^$/ 将与所有空行匹配 
/}^/ 将与以 '}'(无空格)结束的任何行匹配 
/} *^/ 将与以 '}' 后面跟有零或多个空格结束的任何行匹配 
/[abc]/ 将与包含小写 'a'、'b' 或 'c' 的任何行匹配 
/^[abc]/ 将与以 'a'、'b' 或 'c'开始的任何行匹配


在这些示例中,鼓励您尝试几个。花一些时间熟悉规则表达式,然后尝试几个自己创建的规则表达式。可以如下使用 /^#/:
 
  1. $ sed -e '/^#/d' /etc/services | more
复制代码
这将导致 sed 删除任何匹配的行。删除以#开头的行

另一个例子:
  1. $ sed -n -e '/^#/p' /path/to/my/test/file | more
复制代码
请注意新的 '-n' 选项,该选项告诉 sed 除非明确要求打印模式空间,否则不这样做。您还会注意到,我们用 'p' 命令替换了 'd' 命令,如您所猜想的那样,这明确要求 sed 打印模式空间。就这样,将只打印匹配部分。打印以#开头的行


有关地址的更多内容
目前为止,我们已经看到了行地址、行范围地址和 ^# 地址。但是,还有更多的可能。我们可以指定两个用逗号分开的规则表达式,sed 将与所有从匹配第一个规则表达式的第一行开始,到匹配第二个规则表达式的行结束(包括该行)的所有行匹配。例如,以下命令将打印从包含 "BEGIN" 的行开始,并且以包含 "END" 的行结束的文本块:
 
  1. $ sed -n -e '/BEGIN/,/^END/p' /my/test/file | more
复制代码

如果没发现 "BEGIN",那么将不打印数据。如果发现了 "BEGIN",但是在这之后的所有行中都没发现 "END",那么将打印所有后续行。发生这种情况是因为 sed 面向流的特性 -- 它不知道是否会出现 "END"。

C 源代码示例
如果只要打印 C 源文件中的 main() 函数,可输入:
 
  1. $ sed -n -e '/main[[:space:]]*(/,/^}/p' sourcefile.c | more
复制代码

以main后面跟空格或制表键,以(开头,}结尾的

该命令有两个规则表达式 '/main[[]]*(/' 和 '/^}/',以及一个命令 'p'。第一个规则表达式将与后面依次跟有任意数量的空格或制表键以及开始圆括号的字符串 "main" 匹配。这应该与一般 ANSI C main() 声明的开始匹配。

在这个特别的规则表达式中,出现了 '[[]]' 字符类。这只是一个特殊的关键字,它告诉 sed 与 TAB 或空格匹配。如果愿意的话,可以不输入 '[[]]',而输入 '[',然后是空格字母,然后是 -V,然后再输入制表键字母和 ']' -- Control-V 告诉 bash 要插入“真正”的制表键,而不是执行命令扩展。使用 '[[]]' 命令类(特别是在脚本中)会更清楚。

好,现在看一下第二个 regexp。'/^}' 将与任何出现在新行行首的 '}' 字符匹配。如果代码的格式很好,那么这将与 main() 函数的结束花括号匹配。如果格式不好,则不会正确匹配 -- 这是执行模式匹配任务的一件棘手之事。

因为是处于 '-n' 安静方式,所以 'p' 命令还是完成其惯有任务,即明确告诉 sed 打印该行。试着对 C 源文件运行该命令 -- 它应该输出整个 main() { } 块,包括开始的 "main()" 和结束的 '}'。
 

 

 

 

 
  

转载于:https://my.oschina.net/u/3803405/blog/1791044

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值