专注于互联网--专注于架构

最新标签
网站地图
文章索引
Rss订阅

首页 »嵌入式开发 » sed最后一行: sed 实例(一) »正文

sed最后一行: sed 实例(一)

来源: 发布时间:星期四, 2008年12月11日 浏览:19次 评论:0
在本文章系列中Daniel Robbins 将为您演示如何使用功能十分强大(但常被遗忘) UNIX 流编辑器 sedsed 是用批处理方式编辑文件或以十分有效方式创建 shell 脚本以修改现有文件理想工具

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

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

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

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

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

最新 GNU sed
8HYfbaiducukNpD在研究这篇文章之时我注意到:几个在线 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 之后我就完全准备好了

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

sed 示例
8HYfbaiducukNpDsed 通过对输入数据执行任意数量用户指定编辑操作(“命令”)来工作sed 是基于行因此按顺序对每行执行命令然后sed 将其结果写入标准输出 (stdout)它不修改任何输入文件

让我们看些示例头几个会有些奇怪我要用它们演示 sed 如何工作而不是执行任何有用任务然而如果您是 sed 新手那么理解它们是十分重要下面是第个示例:

$ sed -e 'd' /etc/services

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

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

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

个 sed 示例
8HYfbaiducukNpD下面是使用 sed 从输出流除去 /etc/services 文件第示例:


8HYfbaiducukNpD$ sed -e '1d' /etc/services | more


8HYfbaiducukNpD如您所见除了前面有 '1' 之外该命令与第个 'd' 命令十分类似如果您猜到 '1' 指是第那您就猜对了与第个示例中只使用 'd' 不同次使用 'd' 前面有个可选数字地址通过使用地址可以告诉 sed 只对某或某些特定行进行编辑

地址范围
8HYfbaiducukNpD现在让我们看下如何指定地址范围在本例中sed 将删除输出第 1 到 10 行:

$ sed -e '1,10d' /etc/services | more


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

带规则表达式地址
8HYfbaiducukNpD现在演示个更有用示例假设要查看 /etc/services 文件内容但是对查看其中包括注释部分不感兴趣如您所知可以通过以 '#' 开头行在 /etc/services 文件中放置注释为了避免注释我们希望 sed 删除以 '#' 开始以下是具体做法:


8HYfbaiducukNpD$ sed -e '/^#/d' /etc/services | more


8HYfbaiducukNpD试下该例看看发生了什么您将注意到sed 成功完成了预期任务现在让我们分析发生情况

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

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

规则表达式复习
8HYfbaiducukNpD可以使用规则表达式来表示可能会在文本中发现模式您在 shell 命令行中用过 '*' 吗?这种用法与规则表达式类似但并不相同下面是可以在规则表达式中使用特殊

描述
8HYfbaiducukNpD与行首匹配
8HYfbaiducukNpD与行末尾匹配
8HYfbaiducukNpD与任匹配
8HYfbaiducukNpD将与前零或多个出现匹配
8HYfbaiducukNpD[ ] 与 [ ] 之内所有匹配

感受规则表达式最好方法可能是看几个示例所有这些示例都将被 sed 作为合法地址接受这些地址出现在命令左边下面是几个示例:

规则
8HYfbaiducukNpD表达式 描述
8HYfbaiducukNpD/./ 将与包含至少任何行匹配
8HYfbaiducukNpD/../ 将与包含至少两个任何行匹配
8HYfbaiducukNpD/^#/ 将与以 '#' 开始任何行匹配
8HYfbaiducukNpD/^$/ 将与所有空行匹配
8HYfbaiducukNpD/}^/ 将与以 '}'(无空格)结束任何行匹配
8HYfbaiducukNpD/} *^/ 将与以 '}' 后面跟有零或多个空格结束任何行匹配
8HYfbaiducukNpD/[abc]/ 将与包含小写 'a'、'b' 或 'c' 任何行匹配
8HYfbaiducukNpD/^[abc]/ 将与以 'a'、'b' 或 'c'开始任何行匹配

在这些示例中鼓励您尝试几个些时间熟悉规则表达式然后尝试几个自己创建规则表达式可以如下使用 regexp:


8HYfbaiducukNpD$ sed -e '/regexp/d' /path/to/my/test/file | more


8HYfbaiducukNpD这将导致 sed 删除任何匹配然而通过告诉 sed打印 regexp 匹配并删除不匹配内容而不是与之相反方法会更有利于熟悉规则表达式可以用以下命令这样做:


8HYfbaiducukNpD$ sed -n -e '/regexp/p' /path/to/my/test/file | more


8HYfbaiducukNpD请注意新 '-n' 选项该选项告诉 sed 除非明确要求打印模式空间否则不这样做您还会注意到我们用 'p' 命令替换了 'd' 命令如您所猜想那样这明确要求 sed 打印模式空间就这样将只打印匹配部分

有关地址更多内容
8HYfbaiducukNpD目前为止我们已经看到了行地址、行范围地址和 regexp 地址但是还有更多可能我们可以指定两个用逗号分开规则表达式sed 将与所有从匹配第个规则表达式行开始到匹配第二个规则表达式行结束(包括该行)所有行匹配例如以下命令将打印从包含 "BEGIN" 行开始并且以包含 "END" 行结束文本块:


8HYfbaiducukNpD$ sed -n -e '/BEGIN/,/END/p' /my/test/file | more


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

C 源代码示例
8HYfbaiducukNpD如果只要打印 C 源文件中 可输入:


8HYfbaiducukNpD$ sed -n -e '/[[:space:]]*(/,/^}/p' sourcefile.c | more


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

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

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

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

0

相关文章

读者评论

发表评论

  • 昵称:
  • 内容: