sed 实例.docx
- 文档编号:8924394
- 上传时间:2023-02-02
- 格式:DOCX
- 页数:24
- 大小:33.21KB
sed 实例.docx
《sed 实例.docx》由会员分享,可在线阅读,更多相关《sed 实例.docx(24页珍藏版)》请在冰豆网上搜索。
sed实例
sed实例第一部分
挑选编辑器
在UNIX世界中有很多文本编辑器可供我们选择。
思考一下--vi、emacs和jed以及很多其它工具都会浮现在脑海中。
我们都有自己已逐渐了解并且喜爱的编辑器(以及我们喜爱的组合键)。
有了可信赖的编辑器,我们可以轻松处理任何数量与UNIX有关的管理或编程任务。
虽然交互式编辑器很棒,但却有其限制。
尽管其交互式特性可以成为强项,但也有其不足之处。
考虑一下需要对一组文件执行类似更改的情形。
您可能会本能地运行自己所喜爱的编辑器,然后手工执行一组烦琐、重复和耗时的编辑任务。
然而,有一种更好的方法。
进入sed
如果可以使编辑文件的过程自动化,以便用“批处理”方式编辑文件,甚至编写可以对现有文件进行复杂更改的脚本,那将太好了。
幸运的是,对于这种情况,有一种更好的方法--这种更好的方法称为"sed"。
sed是一种几乎包括在所有UNIX平台(包括Linux)的轻量级流编辑器。
sed有许多很好的特性。
首先,它相当小巧,通常要比您所喜爱的脚本语言小很多倍。
其次,因为sed是一种流编辑器,所以,它可以对从如管道这样的标准输入接收的数据进行编辑。
因此,无需将要编辑的数据存储在磁盘上的文件中。
因为可以轻易将数据管道输出到sed,所以,将sed用作强大的shell脚本中长而复杂的管道很容易。
试一下用您所喜爱的编辑器去那样做。
GNUsed
对Linux用户来说幸运的是,最好的sed版本之一恰好是GNUsed,其当前版本是3.02。
每一个Linux发行版都有(或至少应该有)GNUsed。
GNUsed之所以流行不仅因为可以自由分发其源代码,还因为它恰巧有许多对POSIXsed标准便利、省时的扩展。
另外,GNU没有sed早期专门版本的很多限制,如行长度限制--GNU可以轻松处理任意长度的行。
最新的GNUsed
在研究这篇文章之时我注意到:
几个在线sed爱好者提到GNUsed3.02a。
奇怪的是,在ftp.gnu.org(有关这些链接,请参阅参考资料)上找不到sed3.02a,所以,我只得在别处寻找。
我在alpha.gnu.org的/pub/sed中找到了它。
于是我高兴地将其下载、编译然后安装,而几分钟后我发现最新的sed版本却是3.02.80--可在alpha.gnu.org上3.02a源代码旁边找到其源代码。
安装完GNUsed3.02.80之后,我就完全准备好了。
alpha.gnu.org
alpha.gnu.org(请参阅参考资料)是新的和实验性GNU源代码的所在地。
然而,您还会在那里发现许多优秀、稳定的源代码。
出于某种原因,不是许多GNU开发人员忘记将稳定的源代码移至ftp.gnu.org,就是它们的"beta"期间格外长(2年!
)。
例如,sed3.02a已有两年,甚至3.02.80也有一年,但它们仍不能(在2000年8月写本文章时)在ftp.gnu.org上获得。
正确的sed
在本系列中,将使用GNUsed3.02.80。
在即将出现的本系列后续文章中,某些(但非常少)最高级的示例将不能在GNUsed3.02或3.02a中使用。
如果您使用的不是GNUsed,那么结果可能会不同。
现在为什么不花些时间安装GNUsed3.02.80呢?
那样,不仅可以为本系列的余下部分作好准备,而且还可以使用可能是目前最好的sed。
sed示例
sed通过对输入数据执行任意数量用户指定的编辑操作(“命令”)来工作。
sed是基于行的,因此按顺序对每一行执行命令。
然后,sed将其结果写入标准输出(stdout),它不修改任何输入文件。
让我们看一些示例。
头几个会有些奇怪,因为我要用它们演示sed如何工作,而不是执行任何有用的任务。
然而,如果您是sed新手,那么理解它们是十分重要的。
下面是第一个示例:
$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文件第一行的示例:
$sed-e'1d'/etc/services|more
如您所见,除了前面有'1'之外,该命令与第一个'd'命令十分类似。
如果您猜到'1'指的是第一行,那您就猜对了。
与第一个示例中只使用'd'不同的是,这一次使用的'd'前面有一个可选的数字地址。
通过使用地址,可以告诉sed只对某一或某些特定行进行编辑。
地址范围
现在,让我们看一下如何指定地址范围。
在本例中,sed将删除输出的第1到10行:
$sed-e'1,10d'/etc/services|more
当用逗号将两个地址分开时,sed将把后面的命令应用到从第一个地址开始、到第二个地址结束的范围。
在本例中,将'd'命令应用到第1到10行(包括这两行)。
所有其它行都被忽略。
带规则表达式的地址
现在演示一个更有用的示例。
假设要查看/etc/services文件的内容,但是对查看其中包括的注释部分不感兴趣。
如您所知,可以通过以'#'字符开头的行在/etc/services文件中放置注释。
为了避免注释,我们希望sed删除以'#'开始的行。
以下是具体做法:
$sed-e'/^#/d'/etc/services|more
试一下该例,看看发生了什么。
您将注意到,sed成功完成了预期任务。
现在,让我们分析发生的情况。
要理解'/^#/d'命令,首先需要对其剖析。
首先,让我们除去'd'--这是我们前面所使用的同一个删除行命令。
新增加的是'/^#/'部分,它是一种新的规则表达式地址。
规则表达式地址总是由斜杠括起。
它们指定一种模式,紧跟在规则表达式地址之后的命令将仅适用于正好与该特定模式匹配的行。
因此,'/^#/'是一个规则表达式。
但是,它做些什么呢?
很明显,现在该复习规则表达式了。
规则表达式复习
可以使用规则表达式来表示可能会在文本中发现的模式。
您在shell命令行中用过'*'字符吗?
这种用法与规则表达式类似,但并不相同。
下面是可以在规则表达式中使用的特殊字符:
字符
描述
^
与行首匹配如^c
$
与行末尾匹配如$c
.
与任一个字符(单字符)匹配
*
将与前一个字符的零或多个出现匹配(一个单字符后跟*,匹配0或多个此字符)
[]
\
与[]之内的所有字符匹配,可以是单字也可以是字符序列,也可以使用-表示字符范围,如[1-5]
用来匹配一个元字符的特殊含义
感受规则表达式的最好方法可能是看几个示例。
所有这些示例都将被sed作为合法地址接受,这些地址出现在命令的左边。
下面是几个示例:
规则表达式
描述
/./
将与包含至少一个字符的任何行匹配
/../
将与包含至少两个字符的任何行匹配
/^#/
将与以'#'开始的任何行匹配
/^$/
将与所有空行匹配
/}^/
将与以'}'(无空格)结束的任何行匹配
/}*^/
将与以'}'后面跟有零或多个空格结束的任何行匹配
/[abc]/
将与包含小写'a'、'b'或'c'的任何行匹配
/^[abc]/
将与以'a'、'b'或'c'开始的任何行匹配
在这些示例中,鼓励您尝试几个。
花一些时间熟悉规则表达式,然后尝试几个自己创建的规则表达式。
可以如下使用regexp:
$sed-e'/regexp/d'/path/to/my/test/file|more
这将导致sed删除任何匹配的行。
然而,通过告诉sed打印regexp匹配并删除不匹配的内容,而不是与之相反的方法,会更有利于熟悉规则表达式。
可以用以下命令这样做:
$sed-n-e'/regexp/p'/path/to/my/test/file|more
请注意新的'-n'选项,该选项告诉sed除非明确要求打印模式空间,否则不这样做。
您还会注意到,我们用'p'命令替换了'd'命令,如您所猜想的那样,这明确要求sed打印模式空间。
就这样,将只打印匹配部分。
有关地址的更多内容
目前为止,我们已经看到了行地址、行范围地址和regexp地址。
但是,还有更多的可能。
我们可以指定两个用逗号分开的规则表达式,sed将与所有从匹配第一个规则表达式的第一行开始,到匹配第二个规则表达式的行结束(包括该行)的所有行匹配。
例如,以下命令将打印从包含"BEGIN"的行开始,并且以包含"END"的行结束的文本块:
$sed-n-e'/BEGIN/,/END/p'/my/test/file|more
如果没发现"BEGIN",那么将不打印数据。
如果发现了"BEGIN",但是在这之后的所有行中都没发现"END",那么将打印所有后续行。
发生这种情况是因为sed面向流的特性--它不知道是否会出现"END"。
C源代码示例
如果只要打印C源文件中的main()函数,可输入:
$sed-n-e'/main[[:
space:
]]*(/,/^}/p'sourcefile.c|more
该命令有两个规则表达式'/main[[:
space:
]]*(/'和'/^}/',以及一个命令'p'。
第一个规则表达式将与后面依次跟有任意数量的空格或制表键以及开始圆括号的字符串"main"匹配。
这应该与一般ANSICmain()声明的开始匹配。
在这个特别的规则表达式中,出现了'[[:
space:
]]'字符类。
这只是一个特殊的关键字,它告诉sed与TAB或空格匹配。
如果愿意的话,可以不输入'[[:
space:
]]',而输入'[',然后是空格字母,然后是-V,然后再输入制表键字母和']'--Control-V告诉bash要插入“真正”的制表键,而不是执行命令扩展。
使用'[[:
space:
]]'命令类(特别是在脚本中)会更清楚。
好,现在看一下第二个regexp。
'/^}'将与任何出现在新行行首的'}'字符匹配。
如果代码的格式很好,那么这将与main()函数的结束花括号匹配。
如果格式不好,则不会正确匹配--这是执行模式匹配任务的一件棘手之事。
因为是处于'-n'安静方式,所以'p'命令还是完成其惯有任务,即明确告诉sed打印该行。
试着对C源文件运行该命令--它应该输出整个main(){}块,包括开始的"main()"和结束的'}'。
下一篇
既然已经触及了基本知识,我们将在后两篇文章中加快步伐。
如果想看一些更丰富的sed资料,请耐心一些--马上就有!
同时,您可能想查看下列sed和规则表达式资源。
sed实例第二部分
sed是十分强大和小巧的文本流编辑器。
在本文章系列的第二篇中,DanielRobbins为您演示如何使用sed来执行字符串替换、创建更大的sed脚本以及如何使用sed的附加、插入和更改行命令。
sed是很有用(但常被遗忘)的UNIX流编辑器。
在以批处理方式编辑文件或以有效方式创建shell脚本来修改现有文件方面,它是十分理想的工具。
本文是前一篇介绍sed文章的续篇。
替换!
让我们看一下sed最有用的命令之一,替换命令。
使用该命令,可以将特定字符串或匹配的规则表达式用另一个字符串替换。
下面是该命令最基本用法的示例:
$sed-e's/foo/bar/'myfile.txt
上面的命令将myfile.txt中每行第一次出现的'foo'(如果有的话)用字符串'bar'替换,然后将该文件内容输出到标准输出。
请注意,我说的是每行第一次出现,尽管这通常不是您想要的。
在进行字符串替换时,通常想执行全局替换。
也就是说,要替换每行中的所有出现,如下所示:
$sed-e's/foo/bar/g'myfile.txt
在最后一个斜杠之后附加的'g'选项告诉sed执行全局替换。
关于's///'替换命令,还有其它几件要了解的事。
首先,它是一个命令,并且只是一个命令,在所有上例中都没有指定地址。
这意味着,'s///'还可以与地址一起使用来控制要将命令应用到哪些行,如下所示:
$sed-e'1,10s/enchantment/entrapment/g'myfile2.txt
上例将导致用短语'entrapment'替换所有出现的短语'enchantment',但是只在第一到第十行(包括这两行)上这样做。
$sed-e'/^$/,/^END/s/hills/mountains/g'myfile3.txt
该例将用'mountains'替换'hills',但是,只从空行开始,到以三个字符'END'开始的行结束(包括这两行)的文本块上这样做。
关于's///'命令的另一个妙处是'/'分隔符有许多替换选项。
如果正在执行字符串替换,并且规则表达式或替换字符串中有许多斜杠,则可以通过在's'之后指定一个不同的字符来更改分隔符。
例如,下例将把所有出现的/usr/local替换成/usr:
$sed-e's:
/usr/local:
/usr:
g'mylist.txt
在该例中,使用冒号作为分隔符。
如果需要在规则表达式中指定分隔符字符,可以在它前面加入反斜杠。
规则表达式混乱
目前为止,我们只执行了简单的字符串替换。
虽然这很方便,但是我们还可以匹配规则表达式。
例如,以下sed命令将匹配从'<'开始、到'>'结束、并且在其中包含任意数量字符的短语。
下例将删除该短语(用空字符串替换):
$sed-e's/<.*>//g'myfile.html
这是要从文件除去HTML标记的第一个很好的sed脚本尝试,但是由于规则表达式的特有规则,它不会很好地工作。
原因何在?
当sed试图在行中匹配规则表达式时,它要在行中查找最长的匹配。
在我的前一篇sed文章中,这不成问题,因为我们使用的是'd'和'p'命令,这些命令总要删除或打印整行。
但是,在使用's///'命令时,确实有很大不同,因为规则表达式匹配的整个部分将被目标字符串替换,或者,在本例中,被删除。
这意味着,上例将把下行:
ThisiswhatImeant.
变成:
meant.
我们要的不是这个,而是:
ThisiswhatImeant.
幸运的是,有一种简便方法来纠正该问题。
我们不输入“'<'字符后面跟有一些字符并以'>'字符结束”的规则表达式,而只需输入一个“'<'字符后面跟有任意数量非'>'字符并以'>'字符结束”的规则表达式。
这将与最短、而不是最长的可能性匹配。
新命令如下:
$sed-e's/<[^>]*>//g'myfile.html
在上例中,'[^>]'指定“非'>'”字符,其后的'*'完成该表达式以表示“零或多个非'>'字符”。
对几个html文件测试该命令,将它们管道输出到"more",然后仔细查看其结果。
更多字符匹配
'[]'规则表达式语法还有一些附加选项。
要指定字符范围,只要字符不在第一个或最后一个位置,就可以使用'-',如下所示:
'[a-x]*'
这将匹配零或多个全部为'a'、'b'、'c'...'v'、'w'、'x'的字符。
另外,可以使用'[:
space:
]'字符类来匹配空格。
以下是可用字符类的相当完整的列表:
字符类
描述
[:
alnum:
]
字母数字[a-zA-Z0-9]
[:
alpha:
]
字母[a-zA-Z]
[:
blank:
]
空格或制表键
[:
cntrl:
]
任何控制字符
[:
digit:
]
数字[0-9]
[:
graph:
]
任何可视字符(无空格)
[:
lower:
]
小写[a-z]
[:
print:
]
非控制字符
[:
punct:
]
标点字符
[:
space:
]
空格
[:
upper:
]
大写[A-Z]
[:
xdigit:
]
十六进制数字[0-9a-fA-F]
尽可能使用字符类是很有利的,因为它们可以更好地适应非英语locale(包括某些必需的重音字符等等).
高级替换功能
我们已经看到如何执行简单甚至有些复杂的直接替换,但是sed还可以做更多的事。
实际上可以引用匹配规则表达式的部分或全部,并使用这些部分来构造替换字符串。
作为示例,假设您正在回复一条消息。
下例将在每一行前面加上短语"ralphsaid:
":
$sed-e's/.*/ralphsaid:
&/'origmsg.txt
输出如下:
ralphsaid:
HiyaJim,ralphsaid:
ralphsaid:
Isurelikethissedstuff!
ralphsaid:
该例的替换字符串中使用了'&'字符,该字符告诉sed插入整个匹配的规则表达式。
因此,可以将与'.*'匹配的任何内容(行中的零或多个字符的最大组或整行)插入到替换字符串中的任何位置,甚至多次插入。
这非常好,但sed甚至更强大。
那些极好的带反斜杠的圆括号
's///'命令甚至比'&'更好,它允许我们在规则表达式中定义区域,然后可以在替换字符串中引用这些特定区域。
作为示例,假设有一个包含以下文本的文件:
foobaronieenymeenyminylarrycurlymoejimmytheweasel
现在假设要编写一个sed脚本,该脚本将把"eenymeenyminy"替换成"Victoreeny-meenyVonminy"等等。
要这样做,首先要编写一个由空格分隔并与三个字符串匹配的规则表达式。
'.*.*.*'
现在,将在其中每个感兴趣的区域两边插入带反斜杠的圆括号来定义区域:
'\(.*\)\(.*\)\(.*\)'
除了要定义三个可在替换字符串中引用的逻辑区域以外,该规则表达式的工作原理将与第一个规则表达式相同。
下面是最终脚本:
$sed-e's/\(.*\)\(.*\)\(.*\)/Victor\1-\2Von\3/'myfile.txt
如您所见,通过输入'\x'(其中,x是从1开始的区域号)来引用每个由圆括号定界的区域。
输入如下:
Victorfoo-barVononiVictoreeny-meenyVonminyVictorlarry-curlyVonmoeVictorjimmy-theVonweasel
随着对sed越来越熟悉,您可以花最小力气来进行相当强大的文本处理。
您可能想如何使用熟悉的脚本语言来处理这种问题--能用一行代码轻易实现这样的解决方案吗?
组合使用
在开始创建更复杂的sed脚本时,需要有输入多个命令的能力。
有几种方法这样做。
首先,可以在命令之间使用分号。
例如,以下命令系列使用'='命令和'p'命令,'='命令告诉sed打印行号,'p'命令明确告诉sed打印该行(因为处于'-n'模式)。
$sed-n-e'=;p'myfile.txt
无论什么时候指定了两个或更多命令,都按顺序将每个命令应用到文件的每一行。
在上例中,首先将'='命令应用到第1行,然后应用'p'命令。
接着,sed继续处理第2行,并重复该过程。
虽然分号很方便,但是在某些场合下,它不能正常工作。
另一种替换方法是使用两个-e选项来指定两个不同的命令:
$sed-n-e'='-e'p'myfile.txt
然而,在使用更为复杂的附加和插入命令时,甚至多个'-e'选项也不能帮我们的忙。
对于复杂的多行脚本,最好的方法是将命令放入一个单独的文件中。
然后,用-f选项引用该脚本文件:
$sed-n-fmycommands.sedmyfile.txt
这种方法虽然可能不太方便,但总是管用。
一个地址的多个命令
有时,可能要指定应用到一个地址的多个命令。
这在执行许多's///'以变换源文件中的字和语法时特别方便。
要对一个地址执行多个命令,可在文件中输入sed命令,然后使用'{}'字符将这些命令分组,如下所示:
1,20{s/[Ll]inux/GNU\/Linux/gs/samba/Samba/gs/posix/POSIX/g}
上例将把三个替换命令应用到第1行到第20行(包括这两行)。
还可以使用规则表达式地址或者二者的组合:
1,/^END/{s/[Ll]inux/GNU\/Linux/gs/samba/Samba/gs/posix/POSIX/gp}
该例将把'{}'之间的所有命令应用到从第1行开始,到以字母"END"开始的行结束(如果在源文件中没发现"END",则到文件结束)的所有行。
附加、插入和更改行
既然在单独的文件中编写sed脚本,我们可以利用附加、插入和更改行命令。
这些命令将在当前行之后插入一行,在当前行之前插入一行,或者替换模式空间中的当前行。
它们也可以用来将多行插入到输出。
插入行命令用法如下:
i\Thislinewillbeinsertedbeforeeachline
如果不为该命令指定地址,那么它将应用到每一行,并产生如下的输出:
Thislinew
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- sed 实例