totais acumulados com coluna deslocada

totais acumulados com coluna deslocada

Peço desculpas antecipadamente, pois tenho certeza de que este é um problema fácil. No entanto, aqui vai.

cat blah.txt
aa+2
bb+4
cc+10
dd+31

Gostaria de processar blah.txt para produzir o seguinte:

aa+0
bb+2
cc+6
dd+16

A noção aqui é que a primeira coluna pode ser uma lista de músicas e a segunda os horários de início.

Meu palpite era fazer isso usando o awk. Pensei em dois arrays com índices numéricos armazenando $1 e o total acumulado de $2. Minha ideia era mudar o índice numérico dos totais acumulados em 1.

tail -r blah.txt | 
awk -F "+" '{ for(i=0;i<=NR;i++) arr[i+1]+=$2; farr[i]=$1 } END 
{ for(i=NR+1;i>1;i--) {if (i==NR) {print farr[NR] FS 0 } 
else { print farr[i] FS arr[i]}}}'

Isso não é conciso e, além do mais, não funciona. Estou confuso com o fracasso da criação do array acima de tudo.

De qualquer forma, 'nuf disse, alguma pessoa gentil poderia, por favor, acabar com meu sofrimento?

Tom

Responder1

Aqui você vai:

$ awk -F+ '{sum+=$2;printf("%s+%d\n",$1,sum-$2);}' blah.txt
aa+0
bb+2
cc+6
dd+16

Edit1: aqui está uma maneira um pouco mais simples, graças ao Sukminder

$ awk -F+ '{printf("%s+%d\n",$1,sum);sum+=$2}' blah.txt

Edit2: E um pouco mais conciso, graças a Bernhard:

$ awk -F+ '{print $1,sum;sum+=$2}' OFS="+" blah.txt

Edit3: mas o primeiro não exibe 0 na primeira linha, então aqui está uma versão corrigida e um tanto compactada que mostra o caminho mais curto para responder à pergunta de Tom (até que algum novo comentário sugira um melhor):

$ awk -F+ '{print$1,s+0;s+=$2}' OFS=+ blah.txt

Responder2

A melhor maneira de fazer isso é aprender e usar expressões regulares, pois no futuro você economizará muitos problemas ao fazer esse tipo de coisa.

cat blah.txt | gawk 'match($0, /([^0-9]*)([0-9]+)/, ary) {print ary[1] ary[2]-2}'

Você terá que substituir os 2 últimos pela sua variável shift. Você deve observar o uso de gawk. Até onde eu sei, regular awknão pode extrair grupos de expressões regulares.

O que isso faz? Ele faz uma correspondência $0, colocando os resultados em ary, usando uma expressão regular /([^0-9]*)([0-9]+)/, que corresponde a: ([^0-9]*)- 0 ou mais caracteres que não são números e os coloca no primeiro índice da matriz (os parênteses são responsáveis ​​por aquela coisa chamada agrupamento) e, em seguida, ([0-9]+)corresponde ao número de comprimento diferente de zero (e coloca-o como segundo elemento do array).

É claro que isso pode ser mais elaborado, juntamente com alguma verificação de erros, casos especiais de correspondência, etc. - mas eu encorajo você a explorar isso (ou seja, expressões regulares) por conta própria.

informação relacionada