使用 AWK 进行快速而粗略的数据提取

作者:Phil Hughes

许多年前,大概有 20 年了,在 comp Usenet 新闻组上经常有人提到使用最小的工具来完成工作。也就是说,有人会问一个快速而粗略的方法来做某事。接下来的回复通常包括一个 C 解决方案,然后是一个 AWK 解决方案,然后是一个 sed 解决方案等等。

今天,我在解决问题时仍然尝试使用这种理念。在这个特定的例子中,如下所述,我选择了 AWK。如果你们这些老前辈正在阅读这篇文章,我希望你们会提出一个基于 sed 的解决方案。

问题:从电子邮件消息中提取数据

我订阅了每日货币汇率摘要。这是一项免费服务,您也可以订阅 - 只需访问这里。 大部分时间,我会快速浏览一下美元兑欧元的汇率,然后保存电子邮件。 有时候我只是简单地保存消息。我保存它们是因为我一直认为,总有一天我会编写一个程序来显示汇率趋势。但这样做一直是一个低优先级。

前段时间,当我在看一些保存的电子邮件消息时,我意识到,虽然编写一个花哨的图形程序来显示趋势是一项低优先级任务,但编写一个快速而粗略的黑客程序则不然。编写这种黑客程序所需的时间比我花在随机抽样上的时间要少。

我想做的是跟踪日期和数字,然后生成趋势的极简图形显示。 第一步是查看数据。 这是消息的一部分的摘录

>From list@en.ucc.xe.net  Wed Sep 10 12:22:53 2003
...

XE.com's Currency Update Service writes:

Here is today's Currency Update, a service of XE.com. Please read the
copyright, terms of use agreement, and information sections at the
end of this message.  CUS5D0B3D5C16D9
____________________________________________________________________________

If you find our free currency e-mail updates useful, please forward this
message to a friend! Subscribe for free at: http://www.xe.com/cus/
____________________________________________________________________________
<PRE>

Rates as of 2003.09.09 20:46:35 UTC (GMT). Base currency is EUR.

Currency Unit                          EUR per Unit         Units per EUR
================================   ===================   ===================
USD United States Dollars                 0.890585              1.12286     
EUR Euro                                  1.00000               1.00000     
GBP United Kingdom Pounds                 1.41659               0.705920    
CAD Canada Dollars                        0.651411              1.53513     
...

</PRE>

For help reading this mailout, refer to: http://www.xe.com/cus/sample.htm

...

... 行表示我丢弃了很多不感兴趣的行。

我需要从这些电子邮件消息中获取三件事才能生成我的报告

  • “Rates as of”行,以获取日期

  • “USD”行,以获取实际转换率

  • </PRE> 行,告诉我打印信息并清除我的变量。 如果数据良好,我实际上不必清除它们,但这似乎是检测错误数据的好方法。 这是一个快速的 hack,是的,但不是一个令人厌恶的快速 hack。

解决方案

解决方案的数字部分非常简单。 只需获取日期信息和汇率信息。 当我到达 </PRE> 行时,将其打印出来。

图形部分通过打印与汇率相对应的多个加号来实现。 为了获得体面的分辨率,我需要宽幅打印或某种偏移。 我选择了偏移,假设欧元不会跌破 0.90 美元,考虑到它一直走的方向,这非常安全。

最后,我想要一个标题。 使用 AWK 的 BEGIN 块,我放入了几个打印语句。 我不喜欢计算字符,所以我定义了变量over是为了放置在标题信息之前以对齐所有内容的空格数。 这样做仅仅意味着我必须运行程序,看看我离得有多远并调整变量。 这是代码

BEGIN		{
		over = "                 "
		print over, " Cost of Euros in $ by date"
		print over, ".9       1.0       1.1       1.2       1.3"
		print over, "|         |         |         |         |"
		}
/Rates as of/	{ date = $4 }
/^USD/		{ rate = $6 }
/^<\/PRE>/	{
		printf "%s %6.3f ", date, rate
		rc = (rate - .895) * 100
		for (i=0; i < rc; i++) printf "+"
		printf "\n"
		date = "xxx"
		rate = 0
		}

使用邮件文件作为输入运行程序会打印所有结果行,但顺序与邮件文件中的数据顺序相同。 所以是 sort 程序来拯救。 输出中的第一个字段是日期,并且仔细选择标题行的第一个字符意味着一切都正确排序,没有任何选项。 因此,要运行 AWK 程序,请使用

    awk -f cc.as messages | sort 

你就能得到你漂亮的报告。 通过管道将结果传递给more如果您有很多行要查看。

这是来自 AWK 脚本的输出示例


                   Cost of Euros in $ by date
                  .9       1.0       1.1       1.2       1.3
                  |         |         |         |         |
2003.01.02  1.036 +++++++++++++++
...
2003.08.28  1.087 ++++++++++++++++++++
2003.08.29  1.098 +++++++++++++++++++++
2003.08.31  1.099 +++++++++++++++++++++
2003.09.01  1.097 +++++++++++++++++++++
2003.09.02  1.081 +++++++++++++++++++
2003.09.04  1.094 ++++++++++++++++++++
2003.09.05  1.110 ++++++++++++++++++++++
2003.09.07  1.110 ++++++++++++++++++++++
2003.09.08  1.107 ++++++++++++++++++++++
2003.09.09  1.123 +++++++++++++++++++++++
2003.09.10  1.121 +++++++++++++++++++++++
2003.09.11  1.120 +++++++++++++++++++++++
2003.09.12  1.129 ++++++++++++++++++++++++
2003.09.14  1.127 ++++++++++++++++++++++++
2003.09.15  1.128 ++++++++++++++++++++++++
2003.09.16  1.117 +++++++++++++++++++++++
2003.09.17  1.129 ++++++++++++++++++++++++
2003.09.18  1.124 +++++++++++++++++++++++
2003.09.19  1.138 +++++++++++++++++++++++++

好的,sed 专家们,开始吧。

版权所有 (c) 2003, Phil Hughes。 最初发表在 Linux Gazette 第 95 期中。 版权所有 (c) 2003, Specialized Systems Consultants, Inc.

Phil Hughes 是 SSC Publishing, Ltd. 的集团出版人。

加载 Disqus 评论