私のcli fooの一つの弱点はawk
。おそらく、よく書かれたスクリプトを使用すると、次の問題を解決できます。しかし、これが仕事に最適なツールであると確信しており、awk
私の人生ではこれを行う正しい方法はわかりません。
次のデータファイル(Ledger)があるとします。
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つのスペースで区切ります)。
私はこのデータで2つのことが起こりたいと思います。同じコマンドでこれが発生しても、ツールによっては1〜2回のパスで実行する方が簡単です。
負の金額に対するすべての転記は、正の金額の転記後に順番に行われなければなりません。
マイナス金額と重複勘定の転記は統合する必要があります。理想的には、金額を合計することをお勧めしますが、これは通貨形式のため非常に複雑で、金額行のみを再生成できるため、必要ありません。パスごとに1つのユニークなアカウントが統合されていない限り、統合パブリケーションから金額を完全に削除するだけで十分です。
結果は次のようになります。
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
コメントを使用すると、重複する項目を検索するよりも、この操作が少し複雑になります。
- 最初の取引には2つの異なるアカウントが重複しています。そのうちの1つだけマージして消去する必要があります(両方ともマージすることは可能ですが、一度に1つずつマージしない限り、金額を編集することはできません)。
- 中間取引では統合することはありませんが、すべてのマイナス取引で金額を盲目的に整理するのは間違いです。マージングがないのでクリアする必要は全くありませんが、できるもしそうなら、扱いやすくなります。
この問題をどのように解決しますかawk
?または、Awkが最善の解決策ではない場合は何ですか?ほとんどのスクリプト言語(perl、python、zsh)では、すべてを解析して多次元配列に配置し、正規表現の一致量でソートし、2番目はアカウントのアルファでソートして繰り返し出力します。 、常に最後の金額を削除し、最後の重複項目(存在する場合)のみをマージします。
私はAwkで冗長トランザクションを解析してマージする方法を見つけました。
awk 'NF { if (/^20/) { if (last != $$0) print "\n" $$0; last = $$0 } else { print $$0 } }' |
しかし、今より複雑なawkロジックが私に挑戦されています。
ベストアンサー1
このGNU awkスクリプトは私に適しています。
#! /usr/local/bin/awk -f
BEGIN { FS = "[[:space:]][[:space:]]+" }
function dump() {
for (acct in post) { # dump unmerged postings of current transaction
if (post[acct])
print post[acct];
}
if (merged) { # dump merged posting, if any
printf " %s\n", merged
}
merged = ""; # clear variables for next round
delete post;
txn = "";
}
!NF && txn { # blank line, end of transaction
dump();
print;
next
}
END { # end-of-file, print merged postings of last txn
dump();
}
!txn { # new transaction
txn = $0;
print;
next
}
{
acct = $2;
amt = $3
}
amt ~ /-/ { # negative amounts, keep for later
if (acct in post) { # duplicate entry
if (!merged || merged == acct) { # only merge and clear one duplicate account
post[acct] = "";
merged = acct;
}
else # tack on to existing record without merging
post[acct] = post[acct] "\n" $0
}
else
post[acct] = $0
next
}
1
実行中:
~ ./foo.awk foo
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 $-3.00
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