以下内容基于真实故事,尽管一些名称和细节已被更改。
很久以前,在一个遥远的地方,有一个办公室。由于各种原因,该办公室没有购买速溶咖啡。 办公室里的一些员工聚在一起,决定建立一个“咖啡角”。
咖啡角的成员会购买一些速溶咖啡,其他成员会偿还他们。后来,有些人喝的咖啡比其他人多,因此添加了“半个成员”级别:允许半个成员每周喝有限数量的咖啡,并且支付成员支付金额的一半。
管理这个非常痛苦。 我刚刚读了Unix 编程环境,并想练习我的 AWK 编程。 所以我自愿创建一个系统。
步骤 1:我保留了一个成员及其对咖啡角的欠款的数据库。 我以 AWK 友好的格式进行操作,其中字段用冒号分隔
member:john:1:22
member:jane:0.5:33
member:pratyush:0.5:17
member:jing:1:27
上面的第一个字段标识此行的类型(成员)。 第二个字段是成员的姓名(即,没有 @ 的电子邮件用户名)。 下一个字段是他们的会员级别(full=1 或 half=0.5)。 最后一个字段是他们对咖啡角的欠款。 正数表示他们欠钱,负数表示咖啡角欠他们钱。
步骤 2:我保留了咖啡角的输入和输出日志
payment:jane:33
payment:pratyush:17
bought:john:60
payback:john:50
简支付了 33 美元,Pratyush 支付了 17 美元,约翰购买了价值 60 美元的咖啡,咖啡角支付了约翰 50 美元。
步骤 3:我准备好编写一些代码了。 该代码将处理成员和付款,并吐出一个更新的members文件,其中包含新的债务。
#!/usr/bin/env --split-string=awk -F: -f
Shebang (#!) 行需要做一些工作! 我使用 env 命令来允许从 shebang 传递多个参数:具体来说,AWK 的 -F 命令行参数告诉它字段分隔符是什么。
AWK 程序是一系列规则。 (它也可以包含函数定义,但我不需要任何用于咖啡角的函数。)
第一条规则读取 members 文件。 运行命令时,我总是先提供 members 文件,然后再提供 payments 文件。 它使用 AWK 关联数组在 members 数组中记录成员资格级别,在 debt 数组中记录当前债务。
$1 == "member" {
members[$2]=$3
debt[$2]=$4
total_members += $3
}
第二条规则在记录 payment 时减少债务。
$1 == "payment" {
debt[$2] -= $3
}
Payback 则相反:它增加了债务。 这优雅地支持了意外地给某人太多钱的情况。
$1 == "payback" {
debt[$2] += $3
}
最复杂的部分发生在有人为咖啡俱乐部购买("bought")速溶咖啡时。 它被视为付款,并且该人的债务减少了相应的金额。 接下来,它计算每个成员的费用。 它遍历所有成员,并根据他们的会员级别增加他们的债务。
$1 == "bought" {
debt[$2] -= $3
per_member = $3/total_members
for (x in members) {
debt[x] += per_member * members[x]
}
}
END 模式是特殊的:它只发生一次,当 AWK 没有更多行要处理时。 此时,它会吐出新的 members 文件,其中包含更新的债务级别。
END {
for (x in members) {
printf "%s:%s:%s\n", x, members[x], debt[x]
}
}
除了一个遍历成员并向人们发送提醒电子邮件以支付他们的会费(对于正数债务)的脚本之外,该系统在很长一段时间内都在管理咖啡角。
8 条评论