sed 命令 解析及使用

来源:互联网 发布:汽车解剖软件 编辑:程序博客网 时间:2024/05/29 04:19

参考来源:sed命令详解
     sed原理及sed命令格式 ,缓存区,模式空间

Sed工作原理/工作过程

   sed是一个非交互式的流编辑器。所谓非交互式,是指使用sed只能在命令行下输入编辑命令来编辑文本,然后在屏幕上查看输出;而所谓流编辑器,是指sed每次只从文件(或输入)读入一行,然后对该行进行指定的处理,并将结果输出到屏幕(除非取消了屏幕输出又没有显式地使用打印命令),接着读入下一行。整个文件像流水一样被逐行处理然后逐行输出。

  下面我们看一下sed的工作过程。

  sed不是在原输入上直接进行处理的,而是先将读入的行放到缓冲区中,对缓冲区里的内容进行处理,处理完毕后也不会写回原文件(除非用shell的输出重定向来保存结果),而是直接输出到屏幕上。sed运行过程中维护着两个缓冲区,一个是活动的“模式空间(pattern space)”,另一个是起辅助作用的“暂存缓冲区(holding space)”一般情况下,每当运行sed,sed首先把第一行装入模式空间,进行处理后输出到屏幕,然后将第二行装入模式空间替换掉模式空间里原来的内容,然后进行处理,以此类推。

  一般情况下暂存缓冲区是用不到的,但有特殊的命令可以在模式空间与暂存缓冲区之间交换数据,后文将有介绍。由于sed对文本的所有操作都是在缓冲区里进行的,所以不会对原文件造成任何破坏

Sed命令格式

sed [-Options] ['Commands'] filename

  其中,Command是一个sed命令,sed命令一定要被包含在一对单引号中,以免被shell解释,其格式如下:[address-range][sed-command]或[Pattern-to-match][sed-command].

[address-range][sed-command]

[address-range]是指要处理的行的范围,又叫地址范围;
[pattern-to-match]是一个要匹配的模式,是一个正则表达;
sed-command是一个sed命令,用来对指定的行进行处理。

  下面是一个简单的例子:

sed –n '1,3p' students

这个命令将文件students中的第1到3行打印到屏幕。注意,地址范围和sed命令之间没有空格,如果加入空格,sed也会将其忽略。参数-n用来取消默认输出。默认情况下,sed每读入一行到模式空间,无论是否对其进行处理,在读入下一行之前多要将模式空间中的内容输出到屏幕上。参数-n可以用来取消这种默认的输出,只有当用户用命令p时才将指定的行输出到屏幕。如果没有用参数-n而又对指定行执行了p命令,那么这些行将会被打印两次。

地址范围可以是一个数字,这个数字代表了一个行号;也可以是一个用逗号分隔的两个数字表示的范围(包括这两行)。范围可以是数字,正则表达式,或是两者的组合。

####[Pattern-to-match][sed-command]

[pattern-to-match]是一个要匹配的模式,sed将会对所有匹配的行执行sed-command。其实,这里的pattern-to-match也可以看作是一个地址范围,这个地址范围是所有与指定模式匹配的行的行号。因此sed的格式可以归纳为一种:


sed [-Options] ‘[address-range][sed-command]’ filename

示例:

sed -n '1,3 p' a.txt  #sed 命令 -n(sed的命令行选项----取消标准输出) 1,3 (读到缓冲区处理的地址范围) p(sed命令--这个命令表示要怎样处理缓冲区的内容,p是打印输出缓存区内容)sed -n '1,3 s/11/88/p;' a.txt #把1,3行读到缓冲区,处理缓冲区操作是 s/11/88/p 即替换其中的第一个11为88 p是打印结果。这里的[sed-command]就是 s/11/18/p这一句了。sed -n '1,3 s/11/88/gp;' a.txt #把1,3行读到缓冲区,处理缓冲区操作是 s/11/88/gp 即替换其中的所有的(g命令表示所有,正则的全局匹配)11为88 p是打印结果。sed -n 's/11/88/gp' a.txt  #这个命令,由于没有定义范围,sed默认逐行读内容到缓冲区,并使用s/11/88/gp 命令处理。即:每读一行处理一次。

下面看个复杂的:

sed -n ‘:lb; /start/,/end/{/end/! {$! {N;b lb}}}; s/333.*555/8888/; p;’ a.txt


sed -n ’
:lb
/start/,/end/{/end/! {$! {N;b lb}}}
s/333.*555/8888/
p
’ a.txt

上面的解释:

{}是sed命令里的语句块

:lb 是send的label 功能,类似,c语言里的goto lable功能。 lb 是label名称可以自已随便起

:lb; /start/,/end/{/end/! {$! {N;b lb}}}; 可以简化成:lb; /start/,{/end/! {\$! {N;b lb}}}; 表示范围是/start/开始,{/end/! {$! {N;b lb}}};结束的内容读到缓冲区。

{N;b lb} 这一句N是下一行读入缓冲区,然后跳转到lb继续执行。

s/333.*555/8888/; p; 使用这个命令处理缓冲区的内容。

其中:

/end/! {$! {N;b lb}} 中,/end/! 如果不end 那么就 执行这个块{$! {N;b lb}},$!表示如果也不是结尾,就是N循环lb 的label块。 即:只要没有遇见end字符串(/end/!),也没到文档结尾($!),就是一直一行一行读内容到缓冲区。

3.命令与选项

sed命令告诉sed如何处理由地址指定的各输入行,如果没有指定地址则处理所有的输入行。

sed命令

命令 功能 a\ 在当前行后添加一行或多行。多行时除最后一行外,每行末尾需用“\”续行 c\ 用此符号后的新文本替换当前行中的文本。多行时除最后一行外,每行末尾需用”\”续行 i\ 在当前行之前插入文本。多行时除最后一行外,每行末尾需用”\”续行 d 删除行 h 把模式空间里的内容复制到暂存缓冲区 H 把模式空间里的内容追加到暂存缓冲区 g 把暂存缓冲区里的内容复制到模式空间,覆盖原有的内容 G 把暂存缓冲区的内容追加到模式空间里,追加在原有内容的后面 l 列出非打印字符 p 打印行 n 读入下一输入行,并从下一条命令而不是第一条命令开始对其的处理 q 结束或退出sed r 从文件中读取输入行 ! 对所选行以外的所有行应用命令 s 用一个字符串替换另一个 g 在行内进行全局替换     w 将所选的行写入文件 x 交换暂存缓冲区与模式空间的内容 y 将字符替换为另一字符(不能对正则表达式使用y命令) n 读入下一行到模式空间,例:’4{n;d}’ 删除第5行。 N 追加下一行到模式空间,再把当前行和下一行同时应用后面的命令 P 输出多行模式空间的第一部分,直到第一个嵌入的换行符位置。在执行完脚本的最后一个命令之后,模式空间的内容自动输出。P命令经常出现在N命令之后和D命令之前 D 删除模式空间中第一个换行符的内容。它不会导致读入新的输入行,相反,它返回到脚本的顶端,将这些指令应用与模式空间剩余的内容。这3个命令能建立一个输入、输出循环,用来维护两行模式空间,但是一次只输出一行

3.2 sed选项

选项 功能 -e 进行多项编辑,即对输入行应用多条sed命令时使用 -n 取消默认的输出 -f 指定sed脚本的文件名

3.3示例使用

p命令

命令p用于显示模式空间的内容。默认情况下,sed把输入行打印在屏幕上,选项-n用于取消默认的打印操作。当选项-n和命令p同时出现时,sed可打印选定的内容。

sed '/my/p' datafile            

默认情况下,sed把所有输入行都打印在标准输出上。如果某行匹配模式my,p命令将把该行另外打印一遍。

sed -n '/my/p' datafile

选项-n取消sed默认的打印,p命令把匹配模式my的行打印一遍。

d命令

命令d用于删除输入行。sed先将输入行从文件复制到模式空间里,然后对该行执行sed命令,最后将模式空间里的内容显示在屏幕上。如果发出的是命令d,当前模式空间里的输入行会被删除,不被显示。

sed '$d' datafile

删除最后一行,其余的都被显示

sed '/my/d' datafile

删除包含my的行,其余的都被显示

.3 s命令

sed 's/^My/You/g' datafile    #命令末端的g表示在行内进行全局替换,也就是说如果某行出现多个My,所有的My都被替换为You。
sed -n '1,20s/My$/You/gp' datafile     #取消默认输出,处理1到20行里匹配以My结尾的行,把行内所有的My替换为You,并打印到屏幕上。
sed 's#My#Your#g' datafile    #紧跟在s命令后的字符就是查找串和替换串之间的分隔符。分隔符默认为正斜杠,但可以改变。无论什么字符(换行符、反斜线除外),只要紧跟s命令,就成了新的串分隔符。

.4 e选项

-e是编辑命令,用于sed执行多个编辑任务的情况下。在下一行开始编辑前,所有的编辑动作将应用到模式缓冲区中的行上。

sed -e '1,10d' -e 's/My/Your/g' datafile    #选项-e用于进行多重编辑。第一重编辑删除第1-3行。第二重编辑将出现的所有My替换为Your。因为是逐行进行这两项编辑(即这两个命令都在模式空间的当前行上执行),所以编辑命令的顺序会影响结果。[root@db22 tmp]# sed '1,10d' sed-1.txteleventwelvethirteenfourteenfifteen[root@db22 tmp]# sed -e '1,10d' -e 's/teen/tine/g' sed-1.txteleventwelvethirtinefourtinefiftine[root@db22 tmp]# 

.5 r命令

r命令是读命令。sed使用该命令将一个文本文件中的内容加到当前文件的特定位置上。

sed '/My/r introduce.txt' datafile        #如果在文件datafile的某一行匹配到模式My,就在该行后读入文件introduce.txt的内容。如果出现My的行不止一行,则在出现My的各行后都读入introduce.txt文件的内容。

.6 w命令

sed -n '/hrwang/w me.txt' datafile

.7 a\ 命令

a\ 命令是追加命令,追加将添加新文本到文件中当前行(即读入模式缓冲区中的行)的后面。所追加的文本行位于sed命令的下方另起一行。如果要追加的内容超过一行,则每一行都必须以反斜线结束,最后一行除外。最后一行将以引号和文件名结束。

sed '/^hrwang/a\>hrwang and mjfan are husband\>and wife' datafile#如果在datafile文件中发现匹配以hrwang开头的行,则在该行下面追加hrwang and mjfan are husband and wife

.8 i\ 命令

i\ 命令是在当前行的前面插入新的文本。

.9 c\ 命令

sed使用该命令将已有文本修改成新的文本。

.10 n命令

sed使用该命令获取输入文件的下一行,并将其读入到模式缓冲区中,任何sed命令都将应用到匹配行紧接着的下一行上。

sed '/hrwang/{n;s/My/Your/;}' datafile注:如果需要使用多条命令,或者需要在某个地址范围内嵌套地址,就必须用花括号将命令括起来,每行只写一条命令,或这用分号分割同一行中的多条命令。

6.11 y命令
该命令与UNIX/Linux中的tr命令类似,字符按照一对一的方式从左到右进行转换。例如,y/abc/ABC/将把所有小写的a转换成A,小写的b转换成B,小写的c转换成C。

sed '1,20y/hrwang12/HRWANG^$/' datafile#将1到20行内,所有的小写hrwang转换成大写,将1转换成^,将2转换成$。#正则表达式元字符对y命令不起作用。与s命令的分隔符一样,斜线可以被替换成其它的字符。

12 q命令

q命令将导致sed程序退出,不再进行其它的处理。

sed '/hrwang/{s/hrwang/HRWANG/;q;}' datafile

.13 h命令和g命令

h : 把模式空间里的内容复制到暂存缓冲区
H: 把模式空间里的内容追加到暂存缓冲区
g: 把暂存缓冲区里的内容复制到模式空间,覆盖原有的内容
G: 把暂存缓冲区的内容追加到模式空间里,追加在原有内容的后面

#测试使用的文件如下:[root@db22 tmp]# cat sed-2.txtMy name is hrwang.Your name is mjfan.hrwang is mjfan's husband.mjfan is hrwang's wife.

h : 把模式空间里的内容复制到暂存缓冲区
H: 把模式空间里的内容追加到暂存缓冲区

[root@db22 tmp]# sed -e '/hrwang/h' -e '$G' sed-2.txtMy name is hrwang.Your name is mjfan.hrwang is mjfan's husband.mjfan is hrwang's wife.mjfan is hrwang's wife.#根据输出可以看到,h命令把模式空间中的内容复制到holding space时,会覆盖掉原来的内容,所以holding space中只保留了最后一行。[root@db22 tmp]# sed -e '/hrwang/H' -e '$G' sed-2.txtMy name is hrwang.Your name is mjfan.hrwang is mjfan's husband.mjfan is hrwang's wife.My name is hrwang.hrwang is mjfan's husband.mjfan is hrwang's wife.#根据输出可以看到,H命令把pattern space中的内容添加到holding space中[root@db22 tmp]# 

  通过上面两条命令,你会发现h会把原来暂存缓冲区的内容清除,只保存最近一次执行h时保存进去的模式空间的内容。而H命令则把每次匹配hrwnag的行都追加保存在暂存缓冲区。

[root@db22 tmp]# sed -e '/hrwang/H' -e '$g' sed-2.txtMy name is hrwang.Your name is mjfan.hrwang is mjfan's husband.My name is hrwang.hrwang is mjfan's husband.mjfan is hrwang's wife.[root@db22 tmp]# sed -e '/hrwang/H' -e '$G' sed-2.txtMy name is hrwang.Your name is mjfan.hrwang is mjfan's husband.mjfan is hrwang's wife.My name is hrwang.hrwang is mjfan's husband.mjfan is hrwang's wife.

通过上面两条命令,你会发现g把暂存缓冲区中的内容替换掉了模式空间中当前行的内容,此处即替换了最后一行。而G命令则把暂存缓冲区的内容追加到了模式空间的当前行后。此处即追加到了末尾。

.14

[root@db22 tmp]# sed '{1h;2,3H;4G}' sed-2.txtMy name is hrwang.Your name is mjfan.hrwang is mjfan's husband.mjfan is hrwang's wife.My name is hrwang.Your name is mjfan.hrwang is mjfan's husband.[root@db22 tmp]# sed '{1H;2,3h;4G}' sed-2.txtMy name is hrwang.Your name is mjfan.hrwang is mjfan's husband.mjfan is hrwang's wife.hrwang is mjfan's husband.

.观摩别人的案例

sed之:a;N;$!ba构建循环读入文件至pattern

sed之h;H和:a;N;ba使用精解(对段落进行操作)

示例解析1

例子来源:sed循环
   考虑一下我们有一个待处理文本文件books.txt ,它有以下内容:(目前奇数行是书名,偶数行是作者)

A Storm of SwordsGeorge R. R. MartinThe Two TowersJ. R. R. TolkienThe AlchemistPaulo CoelhoThe Fellowship of the RingJ. R. R. TolkienThe PilgrimagePaulo CoelhoA Game of ThronesGeorge R. R. Martin

下面的例子是连接书名,并在一行用逗号分隔作者姓名。然后,它会搜索模式“Paulo”。如果能够匹配,它打印一个连字符(- )在该行的前面,否则跳转到打印行打印标签。

[root@db22 tmp]# sed -n 'h;n;H;xs/\n/,//Paulo/!b Prints/^/- /:Printp' books.txt#执行结果如下:A Storm of Swords,George R. R. MartinThe Two Towers,J. R. R. Tolkien- The Alchemist,Paulo CoelhoThe Fellowship of the Ring,J. R. R. Tolkien- The Pilgrimage,Paulo CoelhoA Game of Thrones,George R. R. Martin

初看起来,上面的脚本可能看起来神秘。让我们看看这是什么情况。

  • 最初sed读入pattern space第一行即书名,holding space为空。

    • h命令:模式缓冲区被复制到holding space。现在,这两个缓冲区包含了本书即标题A Storm of Swords.
    • n命令:读入下一行到模式空间。现在模式缓冲区包含George R. R. Martin
    • H命令:将模式空间的内容添加到暂存缓冲区(holding space)
    • x命令:交换暂存缓冲区与模式空间中的内容,此时可以再次对模式空间应用/pattern/,就像每读入一行到模式空间中那样。
    • 现在模式空间中的内容为:“A Storm of Swords,George R. R. Martin(换行)The Two Towers,J. R. R. Tolkien”
  • s/\n/,/ :将换行符替换为“,”,此时模式空间中的内容就变成了“A Storm of Swords,George R. R. Martin,The Two Towers,J. R. R. Tolkien”

  • /Paulo/!b Print :这一条命令匹配Paulo,目前没有匹配到,所以不执行,直接打印模式空间中的内容:“A Storm of Swords,George R. R. Martin(换行)The Two Towers,J. R. R. Tolkien” ,p命令:打印;完成后继续读入下一行,执行
  • 第三次读入处理后,模式空间的内容为:”The Alchemist,Paulo Coelho” 此时匹配到 /Paulo/!b Print,!是对所选行之外的所有行直接跳转到Print,而匹配到Paulo的行则继续执行s/^/- /,从而完成替换,最后输出- The Alchemist, Paulo Coelho

! :对所选行以外的所有行应用命令

[root@db22 tmp]# sed -n 'h;n;H;xs/\n/,//Paulo/b Prints/^/- /:Printp' books.txt#去掉b Print之前的!号,输出如下:- A Storm of Swords,George R. R. Martin- The Two Towers,J. R. R. TolkienThe Alchemist,Paulo Coelho- The Fellowship of the Ring,J. R. R. TolkienThe Pilgrimage,Paulo Coelho- A Game of Thrones,George R. R. Martin

去掉!则是对匹配到Paulo的行跳转到Print,匹配不到的会执行到替换语句。

为了提高可读性,每个sed命令被放置在一个单独的行。然而,人们可以选择将所有命令在一行中,命令之间用分号分隔,如下所示:

[jerry]$ sed -n 'h;n;H;x;s/\n/, /;/Paulo/!b Print; s/^/- /; :Print;p' books.txt 

sed循环

原创粉丝点击