参考来源: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.txt
eleven
twelve
thirteen
fourteen
fifteen
[root@db22 tmp]# sed -e '1,10d' -e 's/teen/tine/g' sed-1.txt
eleven
twelve
thirtine
fourtine
fiftine
[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.txt
My 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.txt
My 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.txt
My 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.txt
My 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.txt
My 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.txt
My 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.txt
My name is hrwang.
Your name is mjfan.
hrwang is mjfan's husband.
mjfan is hrwang's wife.
hrwang is mjfan's husband.
.观摩别人的案例
示例解析1
例子来源:sed循环
考虑一下我们有一个待处理文本文件books.txt ,它有以下内容:(目前奇数行是书名,偶数行是作者)
A Storm of Swords
George R. R. Martin
The Two Towers
J. R. R. Tolkien
The Alchemist
Paulo Coelho
The Fellowship of the Ring
J. R. R. Tolkien
The Pilgrimage
Paulo Coelho
A Game of Thrones
George R. R. Martin
下面的例子是连接书名,并在一行用逗号分隔作者姓名。然后,它会搜索模式“Paulo”。如果能够匹配,它打印一个连字符(- )在该行的前面,否则跳转到打印行打印标签。
[root@db22 tmp]# sed -n '
h;n;H;x
s/\n/,/
/Paulo/!b Print
s/^/- /
:Print
p' books.txt
#执行结果如下:
A Storm of Swords,George R. R. Martin
The Two Towers,J. R. R. Tolkien
- The Alchemist,Paulo Coelho
The Fellowship of the Ring,J. R. R. Tolkien
- The Pilgrimage,Paulo Coelho
A 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;x
s/\n/,/
/Paulo/b Print
s/^/- /
:Print
p' books.txt
#去掉b Print之前的!号,输出如下:
- A Storm of Swords,George R. R. Martin
- The Two Towers,J. R. R. Tolkien
The Alchemist,Paulo Coelho
- The Fellowship of the Ring,J. R. R. Tolkien
The 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命令的工作原理,包括其非交互式流编辑器的特点和工作过程,以及如何利用模式空间和缓冲区进行文本处理。文章通过讲解sed命令格式 `[address-range][sed-command]`,并提供了多个示例,如d命令、p命令、s命令等,深入阐述了sed的使用方法。此外,还讨论了如何通过选项如-n、-e进行更复杂的文本操作,以及如何利用循环处理文件内容。
1万+

被折叠的 条评论
为什么被折叠?



