Um ponto fraco no meu cli foo é awk
. Eu provavelmente poderia resolver o seguinte com scripts elaborados, mas tenho certeza de que awk
é a melhor ferramenta para o trabalho e, pela minha vida, não consigo descobrir a abordagem correta.
Digamos que eu tenha um arquivo de dados como este (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
Cada parágrafo separado por linha em branco é uma transação , cada linha recuada é um lançamento , cada lançamento tem uma conta e um valor (separado por pelo menos 2 espaços).
Eu quero que duas coisas aconteçam com esses dados. Eu não me importo se isso acontecer no mesmo comando ou não, pode ser mais fácil fazer em uma ou duas passagens, dependendo da ferramenta ...
Todos os lançamentos com valores negativos devem ser organizados após os lançamentos com valores positivos.
Quaisquer lançamentos com valores negativos e contas duplicadas devem ser mesclados. Idealmente, os valores seriam somados, mas isso é muito complicado por causa dos formatos de moeda e não é necessário porque posso regenerar as linhas de valor. A remoção total do valor das postagens mescladas é suficiente, desde que não mais de uma conta única seja mesclada por passagem.
O resultado deve ficar assim:
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
Observações que tornam isso um pouco mais complicado do que apenas uma verificação de duplicatas:
- Na primeira transação, há duas contas diferentes que são duplicadas. Apenas um deles deve ser mesclado e limpo (seria possível mesclar os dois, mas apenas um por passagem ou não poderei corrigir os valores).
- Na transação intermediária não há nada para mesclar, mas seria um erro limpar cegamente os valores de todas as transações negativas. Como não há mesclagem, ela não precisa ser limpa, mas pode ser se isso facilitar o processamento.
Como eu passaria por esse problema em awk
? Ou se Awk não é a melhor solução, qual é? Na maioria das linguagens de script (perl, python, zsh), eu analisaria tudo, jogaria tudo em uma matriz multidimensional, classificaria com base em correspondências regex do valor e secundariamente em alfa para as contas, então iteraria sobre ele para produzi-lo, sempre elimine a última quantia e mescle apenas a última duplicata (se houver).
Observe que eu trabalhei em uma maneira de analisar e mesclar transações duplicadas no Awk outro dia:
awk 'NF { if (/^20/) { if (last != $$0) print "\n" $$0; last = $$0 } else { print $$0 } }' |
Mas uma lógica awk mais complicada está me desafiando agora.
Este script GNU awk funciona para mim:
Em ação:
Com GNU awk para gensub(), arrays de arrays e sorted_in:
.
Se
.
não for o ponto decimal em sua localidade, basta alterarlocaleDecPt="."
para o que for. Se os valores de entrada contiverem, digamos, vírgulas como separadores de milhares, o código que postei não funcionará e você deverá fornecer uma entrada que inclua isso para testar. Codifiquei as larguras do campo de saída para 40 e 10 - você pode calcular facilmente a largura máxima de cada campo e usá-la ou usar guias como OFS e canalizar a saída paracolumn
, mas não parece nada disso ' d ser necessário.Para ser honesto, não entendo seus requisitos sobre o que mesclar e como identificar duplicatas (por exemplo, por que não mesclar todas as duplicatas na primeira transação e por que limpar o valor de uma conta não duplicada na segunda transação?) apenas fundiu os valores para todas as duplicatas e deixou os valores para não duplicados. Se isso não funcionar para você, por favor, esclareça os requisitos em sua pergunta.