Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1919913
  • 博文数量: 261
  • 博客积分: 8073
  • 博客等级: 中将
  • 技术积分: 2363
  • 用 户 组: 普通用户
  • 注册时间: 2006-04-10 15:23
文章分类

全部博文(261)

文章存档

2013年(1)

2012年(1)

2011年(50)

2010年(34)

2009年(4)

2008年(17)

2007年(55)

2006年(99)

分类:

2006-12-06 09:54:26

第二篇 sed 文章中,我提供了一些示例来演示 sed 的工作原理,但是它们当中很少有示例能实际做特别有用的 事。在这篇 sed 系列的最后文章中,我要改变那种方式,并使用 sed 来做实际的事。我将为您显示几个示例,它们不仅演示 sed 的能力,而且还做一些真正巧妙(和方便)的事。例如,在本文的后半部,将为您演示如何设计一个 sed 脚本来将 .QIF 文件从 Intuit 的 Quicken 金融程序转换成具有良好格式的文本文件。在那样做之前,我们将看一下不怎么复杂但却很有用的 sed 脚本。

在 该脚本中,'$' 规则表达式将与行的末尾匹配,而 '\r' 告诉 sed 在其之前插入一个回车。在换行之前插入回车,立即,每一行就以 CR/LF 结束。请注意,仅当使用 GNU sed 3.02.80 或以后的版本时,才会用 CR 替换 '\r'。如果还没有安装 GNU sed 3.02.80,请在我的第一篇 sed 文章中查看如何这样做的说明。

我 已记不清有多少次在下载一些示例脚本或 C 代码之后,却发现它是 DOS/Windows 格式。虽然很多程序不在乎 DOS/Windows 格式的 CR/LF 文本文件,但是有几个程序却在乎 -- 最著名的是 bash,只要一遇到回车,它就会出问题。以下 sed 调用将把 DOS/Windows 格式的文本转换成可信赖的 UNIX 格式:

该脚本的工作原理很简单:替代规则表达式与一行的最末字符匹配,而该字符恰好就是回车。我们用空字符替换它,从而将其从输出中彻底删除。如果使用该脚本并注意到已经删除了输出中每行的最末字符,那么,您就指定了已经是 UNIX 格式的文本文件。也就没必要那样做了!

....将产生以下输出:

可以用以下 sed 脚本达到相同目的:

如果登录到恰巧没有 "tac" 命令的 FreeBSD 系统,将发现该 sed 脚本很有用。虽然方便,但最好还是知道该脚本为什么那样做。让我们对它进行讨论。

来结算我的银行帐户。Quicken 是一个非常好的金融程序,当然会成功地完成这项工作。但是,经过考虑之后,我觉得自己可以轻易编写某个软件来结算我的支票簿。我想,毕竟,我是个软件开发人员!

我 开发了一个很好的小型支票簿结算程序(使用 awk),它通过分析包含我的所有交易的文本文件的语法来计算余额。略微调整之后,我将其改进,以便可以象 Quicken 那样跟踪不同的贷款和借款类别。但是,我还要添加一个特性。最近,我将帐户转移到一家有联机 Web 帐户界面的银行。有一天,我注意到,这家银行的 Web 站点允许以 Quicken 的 .QIF 格式下载我的帐户信息。我马上觉得,如果可以将该信息转换成文本格式,那就太棒了。

在 我的文件中,所有字段都由一个或多个制表符分开,每个交易占据一行。日期之后的下一个字段列出支出类型(如果是收入项,则为 "-")。第三个字段列出收入类型(如果是支出项,则为 "-")。然后,是一个支票号字段(如果为空,则还是 "-"),一个交易完成字段("Y" 或 "N"),一个注释和一个美元金额字段。现在,让我们看一下 QIF 格式。当用文本查看器查看下载的 QIF 文件时,它看起来如下:

浏览过文件之后,不难猜出其格式 -- 忽略第一行,其余的格式如下:

第一个 '1d' 命令删除第一行,第二个命令从输出除去那些讨厌的 '^' 字符。最后一行除去文件中可能存在的任何控制字符。既然在处理外来文件格式,我想消除在中途遇到任何控制字符的风险。到目前为止,一切顺利。现在,要向该基本脚本中添加一些处理功能:

 1d /^^/d s/[[:cntrl:]]//g /^D/ { 
s/^D\(.*\)/\1\tOUTY\tINNY\t/
s/^01/Jan/ s/^02/Feb/
s/^03/Mar/ s/^04/Apr/
s/^05/May/ s/^06/Jun/
s/^07/Jul/ s/^08/Aug/
s/^09/Sep/ s/^10/Oct/
s/^11/Nov/ s/^12/Dec/
s:^\(.*\)/\(.*\)/\(.*\):\2 \1 \3: }

首先,添加一个 '/^D/' 地址,以便 sed 只在遇到 QIF 数据字段的第一个字符 'D' 时才开始处理。当 sed 将这样一行读入其模式空间时,将按顺序执行花括号中的所有命令。

花括号中的第一个命令将把如下行:

变换成:

当然,现在的格式还不完美,但没关系。我们将在进行过程中逐渐细化模式空间的内容。后面 12 行的最后效果是将数据变换成三个字母的格式,最后一行从数据中除去三个斜杠。最后得到这一行:

OUTY 和 INNY 字段是占位符,以后将被替换。现在还不能确定它们,因为如果美元金额为负,将把 OUTY 和 INNY 设置成 "misc" 和 "-",但是,如果美元金额为正,将分别把它们更改成 "-" 和 "inco"。既然还没有读入美元金额,所以,需要暂时使用占位符。

后七行有些复杂,所以将详细讨论它们。首先,连续使用三个 'N' 命令。'N' 命令告诉 sed 将下一行读入输入中,然后将其附加到当前模式空间。这三个 'N' 命令导致将下三行附加到当前模式空间缓冲区,现在这一行看起来如下:

sed 的模式空间变得很难看 -- 需要除去额外的新行,并执行某些附加的格式化。要这样做,将使用替代命令。要匹配的模式为:

这 将与后面依次跟有 'T'、零或多个字符、新行、'N'、任何数量的字符、新行、'P'、以及任何数量字符的新行匹配。呀!这个规则表达式将与刚刚附加到模式空间的三行的全 部内容匹配。但我们要重新格式化该区域,而不是整个替换它。美元金额、支票号(如果有的话)和描述需要出现在替换字符串中。要这样做,我们用带有反斜杠的 圆括号括起那些“感兴趣部分”,以便可以在替换字符串中引用它们(使用 '\1'、'\2\ 和 '\3' 来告诉 sed 将它们插入到何处)。以下是最后的命令:

该命令将我们的行变换成:

虽 然该行正变得好一些,但是,有几件事一看就有点...啊...有趣。首先是那个愚蠢的 "NUMNUM" 字符串 -- 其目的何在?如果查看 sed 脚本的后两行,就会发现其目的,后两行将把 "NUMNUM" 替换成 "-",而把 "NUM""NUM" 替换成 。如您所见,用愚蠢的标记括起支票号允许我们在该字段为空时方便地插入一个 "-"。

附加的十一行使用替代和一些分支功能来美化输出。首先看一下这行:

该行包含一个格式为 "/regexp/b label" 的分支命令。如果模式空间与规则表达式匹配,sed 将分支到 fixnegs 标号。您应该可以轻易找到该标号,它在代码中为 ":fixnegs"。如果规则表达式不匹配,则以常规方式继续处理下一个命令。

既 然您理解该命令本身的工作原理,让我们看一下分支。如果看一下分支规则表达式,将看到它与后面依次跟有 '-'、任意数量的数字、一个 '.'、任意数量的数字和 'AMT' 的字符串 'AMT' 匹配。就象我确信您已猜到一样,该规则表达式专门处理负的美元金额。在这之前,用 'ATM' 括起美元金额,以便以后可以轻易找到它。因为规则表达式只与以 '-' 开始的美元金额匹配,所以,该分支只在恰巧处理借款时才发生。如果正处理贷款,应该将 OUTY 设置成 'misc',将 INNY 设置成 '-',并且应该除去贷款数量前面的负号。如果跟踪代码的流程,将看到实际情况正是这样。如果不执行分支,则用 '-' 替换 OUTY,用 'inco' 替换 INNY。完成了!现在输出行是完美的:

阅读(847) | 评论(0) | 转发(0) |
0

上一篇:sed 实例2

下一篇:FC6下挂载ntfs分区

给主人留下些什么吧!~~