Как взять абсолютное значение с помощью awk?

14

Если у меня есть ниже двух дат:

2015-09-12,2015-08-13

И мне нужно получить количество дней между ними, я буду использовать следующий код:

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

Выход для этого кода будет в то -29время как на самом деле разница29

Eng7
источник

Ответы:

23

Вы можете определить функции awkкак:

awk -F'[-,]' '
  function abs(v) {return v < 0 ? -v : v}
  {print abs(360*($4-$1)+30*($5-$2)+($6-$3))}'
Стефан Шазелас
источник
11

Обычная хитрость для таких ситуаций - использование квадратного корня из квадрата:

awk -F'[-,]' '{print sqrt((360*($4-$1)+30*($5-$2)+($6-$3))^2)}'
jimmij
источник
3
Хотя немного излишне. Обратите внимание, что sqrt(x^2)это хорошо, но sqrt(x)^2может привести к небольшим ошибкам, которые могут вызвать сюрпризы. Для busybox awkего необходимо собрать с включенной поддержкой математики (например, не в пакетах Debian).
Стефан
3
Разве sqrt (x) ^ 2 просто не сработает для отрицательных чисел?
Даниэль МакЛори
1
@DanielMcLaury Вот почему это так sqrt(x^2).
Джимми
@jimmij: Я отвечаю на комментарий к вашему ответу, а не на сам ответ.
Даниэль Маклаури
3

Другой путь:

awk -F'[-,]' '{d=360*($4-$1)+30*($5-$2)+($6-$3);print (d>0)?d:-d}'
cuonglm
источник
Это, наверное, самый эффективный (эффективный) ответ.
Хастур
2

Предполагая, что вы работаете в GNU awk, здесь mktimeесть полезная функция.

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

В последнее время, но вот решение, использующее dateкоманду GNU, которое не основано на фиксированных 30 днях каждый месяц, чтобы все ответы, опубликованные выше, рассматривали его, но ответ Стива .

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

Для ввода ниже:

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

Выход:

30
28
αғsнιη
источник