จะรับค่าสัมบูรณ์โดยใช้ awk ได้อย่างไร


14

หากฉันมีวันที่ด้านล่างสองวัน:

2015-09-12,2015-08-13

และฉันต้องการได้จำนวนวันระหว่างพวกเขาฉันจะใช้รหัสด้านล่าง:

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

ผลลัพธ์สำหรับรหัสนี้จะเป็น-29จริงในขณะที่ความแตกต่างคือ29

คำตอบ:


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)}'

3
แม้ว่า overkill บิต โปรดทราบว่าใช้ได้sqrt(x^2)แต่sqrt(x)^2สามารถแนะนำข้อผิดพลาดเล็ก ๆ ที่อาจทำให้ประหลาดใจ สำหรับ busybox awkจะต้องมีการสร้างโดยเปิดใช้งานการสนับสนุนทางคณิตศาสตร์ (ไม่ใช่ค่าเริ่มต้นในแพ็คเกจ Debian เป็นต้น)
Stéphane Chazelas

3
sqrt (x) ^ 2 จะไม่ล้มเหลวสำหรับตัวเลขลบหรือไม่
Daniel McLaury

1
@DanielMcLaury sqrt(x^2)นั่นเป็นเหตุผลที่มันเป็น
jimmij

@jimmij: ฉันกำลังตอบกลับความคิดเห็นในคำตอบของคุณไม่ใช่เพื่อตอบเอง
Daniel McLaury

3

อีกวิธีหนึ่ง:

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

นี่อาจเป็นคำตอบที่มีประสิทธิภาพที่สุด
Hastur

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
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.