我的 cli foo 中的一个弱点是awk
. 我可能可以通过精心编写的脚本来解决以下问题,但我很确定awk
这是工作的最佳工具,而对于我的一生来说,我无法找出正确的方法。
假设我有一个这样的数据文件(分类帐):
2019/05/31 (MMEX948) Gürmar
Assets:Cash:Marina ₺-28,14
Expenses:Food:Groceries:Meat ₺28,14
Assets:Cash:Marina ₺-28,14
Expenses:Food:Groceries:Meat ₺28,14
Assets:Cash:Marina ₺-3,45
Expenses:Food:Groceries:Basic ₺3,45
Assets:Cash:Marina ₺-15,00
Expenses:Food:Groceries:Produce ₺15,00
2019/06/01 (MMEX932) A101
Assets:Cash:Caleb $-3.00
Assets:Cash:Marina $-2.50
Expenses:Food:Groceries:Basic $5.50
2019/06/01 (MMEX931) Şemikler Pazar Yeri
Assets:Cash:Marina ₺-24,00
Expenses:Food:Groceries:Basic ₺24,00
Assets:Cash:Marina ₺-31,00
Expenses:Food:Groceries:Meat ₺31,00
Assets:Cash:Marina ₺-65,00
Expenses:Food:Groceries:Produce ₺65,00
每个空行分隔的段落是一个事务,每个缩进的行是一个过帐,每个过帐都有一个帐户和一个金额(至少由 2 个空格分隔)。
我希望这些数据发生两件事。我不在乎这些是否发生在同一个命令中,根据工具的不同,一次或两次可能更容易完成......
所有负金额的过账都应安排在正金额的过账之后。
应合并任何负金额和重复帐户的过帐。理想情况下,金额会相加,但由于货币格式,这真的很复杂,而且没有必要,因为我可以重新生成金额行。只要每次通过合并的唯一帐户不超过一个,从合并的帖子中完全删除金额就足够了。
结果应如下所示:
2019/05/31 (MMEX948) Gürmar
Expenses:Food:Groceries:Meat ₺28,14
Expenses:Food:Groceries:Meat ₺28,14
Expenses:Food:Groceries:Basic ₺3,45
Expenses:Food:Groceries:Produce ₺15,00
Assets:Cash:Marina
2019/06/01 (MMEX932) A101
Expenses:Food:Groceries:Basic $5.50
Assets:Cash:Marina $-2.50
Assets:Cash:Caleb
2019/06/01 (MMEX931) Şemikler Pazar Yeri
Expenses:Food:Groceries:Basic ₺24,00
Expenses:Food:Groceries:Meat ₺31,00
Expenses:Food:Groceries:Produce ₺65,00
Assets:Cash:Marina
使这比仅扫描重复项更复杂的注释:
- 在第一笔交易中,有两个不同的账户重复。只应合并和清除其中一个(可以合并两者,但每次只能合并一个,否则我将无法修复数量)。
- 在中间交易中没有什么可合并的,但是盲目地清除所有负交易的金额是错误的。由于没有合并,因此根本不需要清除它,但如果这样做更容易处理,则可能会清除它。
我将如何解决这个问题awk
?或者如果 awk 不是最好的解决方案,那是什么?在大多数脚本语言(perl、python、zsh)中,我会解析所有内容,将其全部放入多维数组中,然后根据 ammount 的正则表达式匹配进行排序,然后根据帐户的 alpha 进行排序,然后对其进行迭代以输出它,始终删除最后一个数量并仅合并最后一个副本(如果有)。
请注意,前几天我确实想出了一种方法来解析和合并 Awk 中的重复事务:
awk 'NF { if (/^20/) { if (last != $$0) print "\n" $$0; last = $$0 } else { print $$0 } }' |
但更复杂的 awk 逻辑现在正在挑战我。
这个 GNU awk 脚本对我有用:
在行动:
使用用于 gensub() 的 GNU awk、数组数组和 sorted_in:
.
如果
.
不是您的语言环境中的小数点,那么只需更改localeDecPt="."
为它是什么。如果您的输入金额包含逗号作为千位分隔符,那么我发布的代码将不起作用,您应该提供包含要测试的输入。我将输出字段宽度硬编码为 40 和 10 - 您可以相当容易地计算每个字段的最大宽度并使用它来代替,或者使用制表符作为 OFS 并将输出传送到,column
但它看起来不像任何一个' d 是必要的。老实说,我不了解您对合并什么以及如何识别重复项的要求(例如,为什么不在第一笔交易中合并所有重复项,为什么在第二笔交易中从一个非重复账户中清除金额?)所以我只是合并了所有重复的金额,并留下了非重复的金额。如果这对您不起作用,请澄清您问题中的要求。