hledger/bin/sortandmergepostings
Caleb Maclennan 1f088324c6 feat: bin: Add AWK script to sort postings and merge duplicates
Co-authored-by: Murukesh Mohanan <murukesh.mohanan@gmail.com>
2023-02-09 23:33:22 -10:00

97 lines
2.1 KiB
Awk
Executable File

#!/usr/bin/awk -f
# Script adapted from suggestions on https://unix.stackexchange.com/a/527004/1925
#
# Passed a ledger file, this will:
# 1. Sort accretion postings before deductions
# 2. Sort postings by account alphabetically
# 3. Merge 1 set of postings with the same account and direction by clearing
# the amount field. Note all posting meta data must also match to merge.
#
# Suggested usage:
# $ sortandmergepostings journal.ledger | hledger -f - print -x
#
# Given that each run will only merge and recalculate amounts on one account per
# transaction it may need to be run multiple times to fully normalize a ledger.
BEGIN { FS = "[[:space:]][[:space:]]+" }
function dump() {
an = asorti(accretions, as)
dn = asorti(deductions, ds)
for (i=1; i<=an; i++) {
postings[length(postings)+1] = accretions[as[i]]
}
for (i=1; i<=dn; i++) {
postings[length(postings)+1] = deductions[ds[i]]
}
for (i in postings) {
posting = postings[i]
split(posting, parts, FS)
currency = parts[3]
gsub(/[[:digit:]., ]+/, "", currency)
if (!inferred && (!merge || merge == parts[2]) && seen[parts[2] currency parts[4]]>1 && parts[3] !~ /@/) {
if (!merge) merged[i] = " " parts[2] " " parts[4]
merge = parts[2]
} else {
merged[i] = posting
}
}
for (i in merged) print merged[i]
if (inferred) print inferred
inferred = ""
merge = ""
delete accretions
delete deductions
delete postings
delete merged
delete seen
}
!NF {
dump()
print
next
}
END {
dump()
}
/^[^[:space:]]/ {
dump()
print $0
next
}
{
postingct++
account = $2
amount = $3
comments = $4
currency = amount
gsub(/[[:digit:]., ]+/, "", currency)
sub(/^[*!] /, "", account)
}
account ~ /^;/ {
print
next
}
!amount {
inferred = $0
next
}
amount !~ /@/ {
seen[account currency comments]++
}
amount !~ /-/ {
accretions[account postingct] = $0
}
amount ~ /-/ {
deductions[account postingct] = $0
}