可以在命令行输入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命令行格式为:
sed [选项] s e d命令输入文件。
复制代码记住在命令行使用s e d命令时,实际命令要加单引号。s e d也允许加双引号。
使用s e d脚本文件,格式为:
sed [选项] -f sed脚本文件输入文件
复制代码要使用第一行具有s e d命令解释器的s e d脚本文件,其格式为:
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’,当对结果很满意时使用这种方法。
$sed 'some-sed-commands' input-file > myoutfile
复制代码2.2 使用sed在文件中查询文本的方式 s e d浏览输入文件时,缺省从第一行开始,有两种方式定位文本:
1) 使用行号,可以是一个简单数字,或是一个行号范围。
2 ) 使用正则表达式
下面是使用s e d定位文本的一些方式。
x x为一行号,如1
x , y 表示行号范围从x到y,如2,5表示从第2行到第5行
/ p a t t e r n / 查询包含模式的行。例如/ d i s k /或/[a-z]/
/ p a t t e r n / p a t t e r n / 查询包含两个模式的行。例如/ d i s k / d i s k s /
p a t t e r n / , x 在给定行号上查询包含模式的行。如/ r i b b o n / , 3
x , / p a t t e r n / 通过行号和模式查询匹配行。3 . / v d u /
x , y ! 查询不包含指定行号x和y的行。1 , 2 !
复制代码2.3 基本sed编辑命令
sed编辑命令
p 打印匹配行
= 显示文件行号
a \ 在定位行号后附加新文本信息
i \ 在定位行号后插入新文本信息
d 删除定位行
c \ 用新文本替换定位文本
s 使用替换模式替换相应模式
r 从另一个文件中读文本
w 写文本到一个文件
q 第一个模式匹配完成后推出或立即推出
l 显示与八进制A S C I I代码等价的控制字符
{ } 在定位行执行的命令组
n 从另一个文件中读文本下一行,并附加在下一行
g 将模式2粘贴到/pattern n/
y 传送字符
n 延续到下一输入行;允许跨行的模式匹配语句
复制代码sed和正则表达式
s e d识别任何基本正则表达式和模式及其行匹配规则。记住规则之一是:如果要定位一特殊字符,必须使用( \)屏蔽其特殊含义
The honeysuckle band played all night long for only $90.
复制代码
6 显示整个文件 要打印整个文件,只需将行范围设为第一行到最后一行1 , $。$意为最后一行。
[sam@Linux_chenwy sam]$ sed -n '1,$p' quote.txt
The honeysuckle band played all night long for only $90.
It was an evening of splendid music and company.
Too bad the disco floor fell through at 23:00.
The local nurse Miss P.Neave was in attendance.
复制代码
7 任意字符 匹配任意字母,后跟任意字母的0次或多次重复,并以i n g结尾,模式为/ . * i n g /。可以使用这个模式查询以i n g结尾的任意单词。
[sam@Linux_chenwy sam]$ sed -n '/.*ing/p' quote.txt
It was an evening of splendid music and company.
复制代码
8 首行 要打印文件第一行,使用行号:
[sam@Linux_chenwy sam]$ sed -n '1p' quote.txt
The honeysuckle band played all night long for only $90.
复制代码
9 最后一行 要打印最后一行,使用$。$是代表最后一行的元字符。
[sam@Linux_chenwy sam]$ sed -n '$p' quote.txt
The local nurse Miss P.Neave was in attendance.
复制代码
10 打印行号 要打印行号,使用等号=。打印模式匹配的行号,使用格式/ p a t t e r n / =。
[sam@Linux_chenwy sam]$ sed -e '/music/=' quote.txt
The honeysuckle band played all night long for only $90.
2
It was an evening of splendid music and company.
Too bad the disco floor fell through at 23:00.
The local nurse Miss P.Neave was in attendance.
复制代码
整个文件都打印出来,并且匹配行打印了行号。如果只关心实际行号,使用- e选项。
[sam@Linux_chenwy sam]$ sed -n '/music/=' quote.txt
2
复制代码
如果只打印行号及匹配行,必须使用两个s e d命令,并使用e选项。第一个命令打印模式匹配行,第二个使用=选项打印行号,格式为sed -n -e /pattern/p -e /pattern/=
[sam@Linux_chenwy sam]$ sed -n -e '/music/p' -e '/music/=' quote.txt
It was an evening of splendid music and company.
2
复制代码
11 附加文本
要附加文本,使用符号a \,可以将指定文本一行或多行附加到指定行。如果不指定文本放置位置, s e d缺省放在每一行后面。附加文本时不能指定范围,只允许一个地址模式。文本附加操作时,结果输出在标准输出上。注意它不能被编辑,因为s e d执行时,首先将文件的一行文本拷贝至缓冲区,在这里s e d编辑命令执行所有操作(不是在初始文件上),因为文本直接输出到标准输出,s e d并无拷贝。 要想在附加操作后编辑文本,必须保存文件,然后运行另一个s e d命令编辑它。这时文件的内容又被移至缓冲区。 附加操作格式如下:
[address]a\
text\
text\
......
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这是一个附加操作,首先应插入一个新行。 第三行是附加操作要加入到拷贝的实际文本。 输出显示附加结果。如果要保存输出,重定向到一个文件。
[sam@chenwy sam]$ cat append.sed
#!/bin/sed -f
/company/ a\
Then suddenly it happed.
复制代码
保存它,增加可执行权限,运行
使用替换修改字符串 如果要附加或修改一个字符串,可以使用(&)命令,&命令保存发现模式以便重新调用它,然后把它放在替换字符串里面。 先给出一个被替换模式,然后是一个准备附加在第一个模式后的另一个模式,并且后面带有&,这样修改模式将放在匹配模式之前。 例如, s e d语句s/nurse/"Hello"&/p 的结果如下
[sam@chenwy sam]$ sed -n 's/nurse/"hello" &/p' quote.txt
The local "hello" nurse Miss P.Neave was in attendance.
复制代码 原句是文本行The local nurse Miss P.Neave was in attendance。 记住模式中要使用空格,因为输出结果表明应加入空格。
还有一个例子:
[sam@chenwy sam]$ sed -n 's/played/from Hockering &/p' quote.txt
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命令中也可以将结果输入文件。格式有点像使用替换命令:
[ a d d r e s s [,address]]w filename
复制代码 ‘w’选项通知s e d将结果写入文件。f i l e n a m e是自解释文件名。 下面有两个例子。
[sam@chenwy sam]$ sed '1,2 w filedt' quote.txt
The honeysuckle band played all night long for only $90.
It was an evening of splendid music and company.
Too bad the disco floor fell through at 23:00.
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。
[sam@chenwy sam]$ cat filedt
The honeysuckle band played all night long for only $90.
It was an evening of splendid music and company.
复制代码
下面例子中查询模式N e a v e,匹配结果行写入文件f i l e d h t。
[sam@chenwy sam]$ sed '/Neave/ w dht' quote.txt
The honeysuckle band played all night long for only $90.
It was an evening of splendid music and company.
Too bad the disco floor fell through at 23:00.
The local nurse Miss P.Neave was in attendance.
复制代码
[sam@chenwy sam]$ cat dht
The local nurse Miss P.Neave was in attendance.
复制代码
从文件中读文本 处理文件时, s e d允许从另一个文件中读文本,并将其文本附加在当前文件。此命令放在模式匹配行后,格式为:
address r filename
复制代码 这里r通知s e d将从另一个文件源中读文本。f i l e n a m e是其文件名。
现在创建一个小文件s e d e x . t x t,内容如下:
[sam@chenwy sam]$ echo "Boom boom went the music" >sedex.txt
[sam@chenwy sam]$ cat sedex.txt
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 /后放置附加文本。本例为第三行。注意所读的文件名需要用单引号括起来。
[sam@chenwy sam]$ sed '/company./r sedex.txt' quote.txt
The honeysuckle band played all night long for only $90.
It was an evening of splendid music and company.
Boom boom went the music
Too bad the disco floor fell through at 23:00.
The local nurse Miss P.Neave was in attendance.
复制代码
匹配后退出 有时需要在模式匹配首次出现后退出s e d,以便执行其他处理脚本。退出命令格式为:
address q
复制代码 下面的例子假定查询模式/ . a . * /,意为任意字符后跟字符a,再跟任意字符0次或任意多次。 查询首次出现模式,然后退出。需要将q放在s e d语句末尾。
[sam@chenwy sam]$ sed '/.a.*/q' quote.txt
The honeysuckle band played all night long for only $90.
进入 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 新手,那么理解它们是十分重要的。下面是第一个示例: