Bagaimana cara mengambil nilai absolut menggunakan awk?

14

Jika saya memiliki di bawah dua tanggal:

2015-09-12,2015-08-13

Dan saya perlu mendapatkan jumlah hari di antara mereka, saya akan menggunakan kode di bawah ini:

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

Output untuk kode ini akan -29sementara sebenarnya perbedaannya29

Eng7
sumber

Jawaban:

23

Anda dapat mendefinisikan fungsi dalam awkseperti:

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

Trik umum untuk situasi seperti ini adalah menggunakan akar kuadrat dari bujur sangkar:

awk -F'[-,]' '{print sqrt((360*($4-$1)+30*($5-$2)+($6-$3))^2)}'
jimmij
sumber
3
Tapi agak berlebihan. Perhatikan itu sqrt(x^2)baik-baik saja, tetapi sqrt(x)^2dapat memperkenalkan kesalahan kecil yang dapat menyebabkan kejutan. Untuk busybox awk, itu harus dibangun dengan dukungan matematika diaktifkan (bukan default dalam paket Debian misalnya).
Stéphane Chazelas
3
Tidakkah sqrt (x) ^ 2 gagal untuk angka negatif?
Daniel McLaury
1
@DanielMcLaury Itu sebabnya sqrt(x^2).
jimmij
@jimmij: Saya membalas komentar atas jawaban Anda, bukan jawaban itu sendiri.
Daniel McLaury
3

Cara lain:

awk -F'[-,]' '{d=360*($4-$1)+30*($5-$2)+($6-$3);print (d>0)?d:-d}'
cuonglm
sumber
Ini mungkin jawaban (kinerja) yang paling efisien.
Hastur
2

Dengan asumsi Anda menggunakan GNU awk, mktimefungsi funky berguna di sini.

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
steve
sumber
1

Untuk terlambat, tapi di sini ada solusi menggunakan dateperintah GNU yang tidak didasarkan pada 30 hari tetap setiap bulan bahwa semua jawaban yang diposting di atas menganggapnya tetapi jawaban 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

Untuk input di bawah ini:

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

Outputnya adalah:

30
28
αғsнιη
sumber