通用线程:Awk 实例( 九 )


print mymonths[1],mymonths[numelements]
……将打印:
Jan Dec
特殊字符串形式
简短注释 -- 调用 length()、sub() 或 gsub() 时,可以去掉最后一个自变量,这样 awk 将对 $0(整个当前行)应用函数调用 。要打印文件中每一行的长度,使用以下 awk 脚本:
{ print length() }
财务上的趣事
几星期前,我决定用 awk 编写自己的支票簿结算程序 。我决定使用简单的 tab 定界文本文件,以便于输入最近的存款和提款记录 。其思路是将这个数据交给 awk 脚本,该脚本会自动合计所有金额,并告诉我余额 。以下是我决定如何将所有交易记录到 "ASCII checkbook" 中:
23 Aug 2000 food - - Y Jimmy"s Buffet 30.25
此文件中的每个字段都由一个或多个 tab 分隔 。在日期(字段 1,$1)之后,有两个字段叫做“费用分类帐”和“收入分类帐” 。以上面这行为例,输入费用时,我在费用字段中放入四个字母的别名,在收入字段中放入 "-"(空白项) 。这表示这一特定项是“食品费用” 。:) 以下是存款的示例:
23 Aug 2000 - inco - Y Boss Man 2001.00
在这个实例中,我在费用分类帐中放入 "-"(空白),在收入分类帐中放入 "inco" 。"inco" 是一般(薪水之类)收入的别名 。使用分类帐别名让我可以按类别生成收入和费用的明细分类帐 。至于记录的其余部分,其它所有字段都是不需加以说明的 。“是否付清?”字段("Y" 或 "N")记录了交易是否已过帐到我的帐户;除此之外,还有一个交易描述,和一个正的美元金额 。
用于计算当前余额的算法不太难 。awk 只需要依次读取每一行 。如果列出了费用分类帐,但没有收入分类帐(为 "-"),那么这一项就是借方 。如果列出了收入分类帐,但没有费用分类帐(为 "-"),那么这一项就是贷方 。而且,如果同时列出了费用和收入分类帐,那么这个金额就是“分类帐转帐”;即,从费用分类帐减去美元金额,并将此金额添加到收入分类帐 。此外,所有这些分类帐都是虚拟的,但对于跟踪收入和支出以及预算却非常有用 。
代码
现在该研究代码了 。我们将从第一行(BEGIN 块和函数定义)开始:
balance,第 1 部分
#!/usr/bin/env awk -fBEGIN { FS="t " months="Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec"}function monthdigit(mymonth) { return (index(months,mymonth) 3)/4}
首先执行 "chmodx myscript" 命令,那么将第一行 "#!..." 添加到任何 awk 脚本将使它可以直接从 shell 中执行 。其余行定义了 BEGIN 块,在 awk 开始处理支票簿文件之前将执行这个代码块 。我们将 FS(字段分隔符)设置成 "t ",它会告诉 awk 字段由一个或多个 tab 分隔 。另外,我们定义了字符串 months,下面将出现的 monthdigit() 函数将使用它 。
最后三行显示了如何定义自己的 awk。格式很简单 -- 输入 "function",再输入名称,然后在括号中输入由逗号分隔的参数 。在此之后,"{ }" 代码块包含了您希望这个函数执行的代码 。所有函数都可以访问全局变量(如 months 变量) 。另外,awk 提供了 "return" 语句,它允许函数返回一个值,并执行类似于 C 和其它语言中 "return" 的操作 。这个特定函数将以 3 个字母字符串格式表示的月份名称转换成等价的数值 。例如,以下代码:
print monthdigit("Mar")
……将打印:
3
现在,让我们讨论其它一些函数 。
财务函数
以下是其它三个执行簿记的函数 。我们即将见到的主代码块将调用这些函数之一,按顺序处理支票簿文件的每一行,从而将相应交易记录到 awk 数组中 。有三种基本交易,贷方 (doincome)、借方 (doexpense) 和转帐 (dotransfer) 。您会发现这三个函数全都接受一个自变量,叫作 mybalance 。mybalance 是二维数组的一个占位符,我们将它作为自变量进行传递 。目前,我们还没有处理过二维数组;但是,在下面可以看到,语法非常简单 。只须用逗号分隔每一维就行了 。

推荐阅读