costs.awk (1517B)
1 #!/usr/bin/awk -f 2 # Copyright 2023 Jacob R. Edwards <jacob@jacobedwards.org> 3 4 function error(msg) { 5 print("error: " msg) > "/dev/stderr"; 6 } 7 8 function die(msg) { 9 status = msg; 10 error(status); 11 exit 1 12 } 13 14 BEGIN { 15 FS = " "; 16 OFS = FS; 17 OFMT = "%.2f"; 18 19 period = 1; 20 amount = 2; 21 name = 3; 22 desc = 4; 23 24 t["daily"] = 1; 25 t["weekly"] = 7; 26 t["bi-weekly"] = 14; 27 t["monthly"] = 365 / 12 # 'spose 30 or 30.4 could produce easier numbers 28 t["quarterly"] = t["monthly"] * 3; 29 t["yearly"] = 365; 30 31 output = "daily"; 32 33 if (ARGC > 1) { 34 if (ARGV[1] != "-") { 35 output = ARGV[1]; 36 if (!(output in t)) 37 die(output " not a valid period"); 38 } 39 delete ARGV[1]; 40 if (ARGC > 1) { 41 prefix = ARGV[2]; 42 delete ARGV[2]; 43 if (ARGC > 3) { 44 die("usage: costs [period [prefix]]") 45 } 46 } 47 } 48 } 49 50 /^[^# ]/ && ! /^$/ && (prefix == "" || index($name, prefix) == 1) { 51 m = 1 52 n = split($period, ts, "/") 53 if (n > 2 || !(ts[1] in t) || (n > 2 && ts[2] == 0)) 54 die($period ": Invalid period") 55 56 if (n > 1) 57 m = ts[2] 58 x = t[ts[1]] * m 59 60 daily = $amount / x 61 62 if (total) { 63 group = "total" 64 } else if (!trim) { 65 group = $name 66 } else { 67 n = split($name, a, "/") 68 if (n <= 1) { 69 group = $name 70 } else { 71 group = a[1] 72 for (i = 2; i <= trim && i <= n; ++i) { 73 group = group "/" a[i] 74 } 75 } 76 } 77 78 groups[group] += daily 79 if (!(group in ordered)) { 80 ordered[group] = 1 81 order[++oi] = group 82 } 83 } 84 85 END { 86 if (status) 87 exit 1 88 for (i = 1; i <= length(order); ++i) { 89 print(order[i], groups[order[i]] * t[output]) 90 } 91 }