Como tirar o valor absoluto usando o awk?


14

Se eu tiver abaixo de duas datas:

2015-09-12,2015-08-13

E preciso obter o número de dias entre eles, usarei o código abaixo:

awk -F'[-,]' '{print 360*($4-$1)+30*($5-$2)+($6-$3)}'

A saída desse código será -29enquanto, na verdade, a diferença for29

Respostas:


23

Você pode definir funções awkcomo:

awk -F'[-,]' '
  function abs(v) {return v < 0 ? -v : v}
  {print abs(360*($4-$1)+30*($5-$2)+($6-$3))}'

11

O truque comum para esse tipo de situação é usar a raiz quadrada do quadrado:

awk -F'[-,]' '{print sqrt((360*($4-$1)+30*($5-$2)+($6-$3))^2)}'

3
Um pouco exagerado. Observe que sqrt(x^2)está bem, mas sqrt(x)^2pode introduzir pequenos erros que podem causar surpresas. Para o busybox awk, ele precisa ser construído com suporte a matemática ativado (não o padrão nos pacotes Debian, por exemplo).
Stéphane Chazelas

3
O sqrt (x) ^ 2 simplesmente falharia em números negativos?
Daniel McLaury

1
@DanielMcLaury É por isso que é sqrt(x^2).
jimmij

@ jimmij: estou respondendo ao comentário da sua resposta, não à resposta em si.
Daniel McLaury

3

Outra maneira:

awk -F'[-,]' '{d=360*($4-$1)+30*($5-$2)+($6-$3);print (d>0)?d:-d}'

Esta é provavelmente a resposta mais eficiente (desempenho).
Hastur

2

Supondo que você esteja no GNU awk, o funkymktime função é útil aqui.

awk -F, '{ gsub(/-/," ",$0);a=(mktime($2 " 23 59 59")-mktime($1 " 00 00 00"))/86400;print a*(a<0?-1:1)}' file.txt
29

1

Até tarde, mas aqui está uma solução usando o datecomando GNU que não se baseia em 30 dias fixos por mês, que todas as respostas postadas acima consideraram a resposta de steve .

awk -F, '{cmd="printf \"%d\n\" $((($(date -d"$1" +%s)-$(date -d"$2" +%s))/86400))"; 
    cmd|getline $0; $0*=($0<0?-1:1); close(cmd)}1' infile

Para a entrada abaixo:

2015-09-12,2015-08-13
2017-02-12,2017-03-12

A saída é:

30
28
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.