Como subtrair linhas, ao contrário, somente se for maior que a linha anterior

1

Estou trabalhando em um script de shell que lerá as linhas de um arquivo, em sentido inverso. Preciso que subtraia a linha anterior da segunda, mas apenas se a segunda for maior. Se for menor, quero apenas o número nessa linha.

Exemplo:

Conteúdo do arquivo:

100
200
300
100
300

Os resultados devem ser:

200     # line 5 - line 4    
100     # line 4 (as it's < line 3) 
100
100

O código que eu estava usando simplesmente para subtrair as linhas anteriormente (sem levar em conta se o valor era > = era:

awk 'p{print $0-p}{p=$0}' inputfile > outputfile

Ainda preciso fazer isso, mas apenas se o valor for maior que a linha anterior.

Eu estava pensando em usar um loop de leitura while, mas atribuir uma variável para cada linha para comparação, ou algo similar, está realmente sobrecarregando meu cérebro. Obrigado antecipadamente!

    
por Tyler 18.08.2015 / 22:30

2 respostas

1

tac é útil para inverter a ordem de linha de um arquivo - (também o BSD tail -r pode inverter a ordem da linha)

tac file | awk 'p { if( p>$1 ) print p-$1; else print p } { p=$1 }' 

Se, por algum motivo, você não puder usar tac ou quiser usar o awk exclusivamente, use awk para ler o arquivo inteiro na memória por meio de uma matriz e END{} processará a matriz na ordem inversa ordem.

awk '{ r[i++]=$0};  END{ for(i=i-1; i>=0; i--) 
       if( r[i+1] ) if( r[i+1]>r[i] ) print r[i+1]-r[i]; else print r[i+1] 
     }' file
    
por 18.08.2015 / 23:49
0

Você pode usar tac para reverter o arquivo e, em seguida, awk para o cálculo. Eu modifiquei seu file para tornar as linhas mais aleatórias.

$ cat file
101
220
303
140
305
$ tac file | awk '{if(last>$0)print last-$0;else print last;last=$0}END{print last}'

165
140
83
119
101

Duas observações:

  • Afinal, você precisa remover a primeira linha (linha vazia) se não precisa disso.
  • No bloco END{} , a primeira linha do arquivo é impressa, remova esse bloco se você não quiser.
por 18.08.2015 / 23:28